最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

header - How do C++ modules hide implementation details when they are in the same file as the interface? - Stack Overflow

programmeradmin2浏览0评论

I’m reading Bjarne Stroustrup’s A Tour of C++ (3rd Edition), which provides a brief introduction to C++20 features. In the book, he shows how export module can eliminate the traditional pattern of having to split declarations and definitions into separate header (.h) and source (.cpp) files. In his book, he introduces a home-brewed vector class module to explain his point:

export module Vector; // defining the module called "Vector"

export class Vector {
public:
    Vector(int s);
    double& operator[](int i);
    int size();
private:
    double* elem; // elem points to an array of sz doubles
    int sz;
};

export bool operator==(const Vector& v1, const Vector& v2) {
    if (v1.size() != v2.size()) 
        return false;
    for (int i = 0; i < v1.size(); ++i) {
        if (v1[i] != v2[i]) 
            return false;
    }
    return true;
}

//Implementations; Supposed to be hidden
Vector::Vector(int s) : elem{new double[s]}, sz{s} {}
double& Vector::operator[](int i) { return elem[i]; }
int Vector::size() { return sz; }

Traditionally, we had to separate header files to expose function signatures (so that consumers of our library know how to call them) and .cpp files to hide implementations. However, with modules, it looks like everything sits in the same file.

My question is: How does having export in a single module file actually hide the implementation from library users? If the implementation is in the same file as the interface, doesn’t that let users (or any consuming compiler) "see" everything by simply looking into the module file?

To put it another way, if I place everything (both the public interface and private implementation) in a single module file, how do I actually hide my private code from clients, while notifying human developers of its function signature, declaration, etc. Isn't text-based header file still needed? I’m specifically concerned about the practical distribution of a closed-source library.

I’m reading Bjarne Stroustrup’s A Tour of C++ (3rd Edition), which provides a brief introduction to C++20 features. In the book, he shows how export module can eliminate the traditional pattern of having to split declarations and definitions into separate header (.h) and source (.cpp) files. In his book, he introduces a home-brewed vector class module to explain his point:

export module Vector; // defining the module called "Vector"

export class Vector {
public:
    Vector(int s);
    double& operator[](int i);
    int size();
private:
    double* elem; // elem points to an array of sz doubles
    int sz;
};

export bool operator==(const Vector& v1, const Vector& v2) {
    if (v1.size() != v2.size()) 
        return false;
    for (int i = 0; i < v1.size(); ++i) {
        if (v1[i] != v2[i]) 
            return false;
    }
    return true;
}

//Implementations; Supposed to be hidden
Vector::Vector(int s) : elem{new double[s]}, sz{s} {}
double& Vector::operator[](int i) { return elem[i]; }
int Vector::size() { return sz; }

Traditionally, we had to separate header files to expose function signatures (so that consumers of our library know how to call them) and .cpp files to hide implementations. However, with modules, it looks like everything sits in the same file.

My question is: How does having export in a single module file actually hide the implementation from library users? If the implementation is in the same file as the interface, doesn’t that let users (or any consuming compiler) "see" everything by simply looking into the module file?

To put it another way, if I place everything (both the public interface and private implementation) in a single module file, how do I actually hide my private code from clients, while notifying human developers of its function signature, declaration, etc. Isn't text-based header file still needed? I’m specifically concerned about the practical distribution of a closed-source library.

Share Improve this question edited Jan 17 at 22:19 K.R.Park asked Jan 17 at 8:25 K.R.ParkK.R.Park 1,1491 gold badge7 silver badges22 bronze badges 9
  • 3 You don't have to put everything in the module interface. You can still have a separate module implementation file, if you want to. Bjarne just says that you can get away with using a single file, not that this is the only option. – BoP Commented Jan 17 at 9:24
  • @BoP Yes, he said, with module, we ‘may’, not ‘must’ put declaration and definition same file without violating encapsulation principle. But I am asking why we ‘may’ do it. Is the module file processed produces human-readable text files along lib or dll files? – K.R.Park Commented Jan 17 at 9:47
  • Have you ever done other compiled languages?(e.g pascal...) What's the difference between public and private members of a class? Similar mechanism has been long awaited for modern C++ modules. The compiled module will eventually embed a header section reflecting exported parts in a tool-chain understandable format. – Red.Wave Commented Jan 18 at 9:50
  • “Have you ever done other compiled languages?” Exactly. C++ without modules looked totally archaic not by itself, but in comparison with other languages, some of them quite old. CLU, Ada, Modula, different Borland Pascal reincarnations, Delphi, Free Pascal, Java, C#, JavaScript with modules... and a lot more. Modules have been commonplace for decades now. People invented exceptions, threading, IPC, and modules, and used them on a regular basis well before C++... – Sergey A Kryukov Commented Jan 19 at 17:28
  • To answer the question, C++ will do the same thing every other language that doesn't separate them does: rely on things like "public/private" and other stuff in order to not expose functionality you don't want – CoffeeTableEspresso Commented Jan 24 at 20:13
 |  Show 4 more comments

3 Answers 3

Reset to default 4 +50

It is important to note that "hide" is normally intended with the sense of avoiding the user "depending" on implementation detais, not neccessarily avoiding the details to be visible.

If you need a module to be distributed without the verbatim implementation details, indeed you cannot use a single file to put both the closed information and the interface. This solution is intented for a different use case.

In other words, you may use this feature, which also means you may not use it.

I just looked through my C++ library, including books by Stroustrup. None mention hiding implementation details as a reason for classes or modules. I realize this is often discussed as a reason, but it is more mythical than real. This is after over 30 years of working with and studying C++.

Templates illustrate precisely the opposite. All the details are present in the header file. Template and non-template code use the "Pointer to implementation" (pImpl) technique to hide the implementation. This again belies the idea that classes are for hiding implementation since you have to work to use this technique.

A regular class does hide implementation details since the member definitions can be in a source file with their declarations in the header. This is a secondary effect since the primary purpose of separate compilation is to improve compilation speed. The same is true of modules with interface and implementation files.

A library hides implementation details since it has header files for the interface and a binary for the implementation. Modules will do the same if the implementation is done in a separate file.

I think you misunderstand what "hiding" means. If your notion is that you want to hide things from the eyes of a human reader, then you are of course right that putting everything into one file defeats part of the purpose. (But, as others have pointed out, this is not necessary with modules -- modules can extend across any number of files.) But if your notion of "hiding" is that it does not allow those who import a module (or #include a header file) to use something, then your example actually achieves its purpose: Because the part at the bottom is not marked as export, the compiler will simply not put these functions and other details into the public part of the module, and you cannot call these functions even if you do import Vector. In this case, this is not relevant because the non-exported part consists of implementations of functions that are declared as exported because you export the class; but, if for example you also declared int myvar; at the bottom, then that variable is not accessible by importers of the module, and the compiler will complain correspondingly.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论