Search code examples
c#c++encapsulation

Avoid putting private fields declaration into c++ header


When I became C# lover, I was little disappointed in C++, because I believed that ancestor solves that I would call interface problem better than it's predecessor. The problem is, you can't get rid of private fields declarations inside class definition, thus encapsulation in it seems not so honest to me. For example:

// Righteous.h
#ifndef RIGHTEOUS_H
#define RIGHTEOUS_H
class Righteous
{
public:
    void Eat(Food* food);
    void Pray(Orison* orison);
    void Love(People* person); // by heart, not physically
private:
    void WatchHornyVideos(); // oops...
    void DoSomethingIllegal(); // hope people will never come here
    void DenyGodExistance(); // else I will probably see Him soon
}
#endif

Even C handles hiding implementation task better, because you can hide it's functions and fields inside .c files, compile them as .lib and deploy header and library without revealing your dirty secrets.

C# meta-class information is nice, though it's not convenient now to extract class definition using text editors like notepad or emacs. Also, C# reflection tools allow anybody to completely decompile .NET assembly, so it's not safe to deploy assemblies, even obfuscated.

In answer to this question, I'd like to see how was it solved in C++ standards from 97th to modern version.


Solution

  • There are two ways to further separate the interface from implementation. Abstract interface:

    class IRighteous
    {
    public:
        virtual void Eat(Food* food) = 0;
        virtual void Pray(Orison* orison) = 0;
        virtual void Love(People* person) = 0;
        virtual ~IRighteous() {}
    };
    

    PIMPL:

    class Righteous
    {
    public:
        void Eat(Food* food);
        void Pray(Orison* orison);
        void Love(People* person);
    
        Righteous(); // To construct RighteousImpl and assign it to the _impl.
        ~Righteous(); // Destructor needs to be defined in cpp where RighteousImpl is defined or included.
    private:
        std::unique_ptr<RighteousImpl> _impl;
    };