Vitality
Vitality

Reputation: 21475

Masking as much as possible of class implementation in C++

I have two classes A and B where B uses objects of class A, something like this

class A {
    private:
        int foo_;

    A(const int &foo): foo_(foo) {}
}

class B {

    // STUFF

    inline C operator()(A a)
}

For the moment, I have put the definition of both in a .h file and the code compiles and executes correctly.

My question is: how much can I mask of the implementation of class A, for example by moving code lines to a .cpp file to be separately compiled and linked? Can I mask the implementation of private members and methods (everything which is not directly accessed by an external user)? How? Which C++ keywords should I use?

Thank you very much in advance.

Upvotes: 1

Views: 341

Answers (3)

Tony Delroy
Tony Delroy

Reputation: 106096

Regarding what the pImpl idiom can hide:

  • you can move all function definitions (the implementation thereof, including constructors and their initialisation lists) into the Impl class
  • which then lets you put private types, data members functions into the Impl class EXCEPT where they affect class behaviour (e.g. private constructors, destructors and operators have implications for the user of the class)
  • you can move definitions and initialisation of class static data members into the implementation file
  • as per Arne's comment, private base classes can typically be moved into the implementation (unless you're using typedefs etc. from them in the public or protected data members, and that's ugly as per his comment!)

Upvotes: 2

Vite Falcon
Vite Falcon

Reputation: 6645

Masking implementations can be done by PIMPL idiom or using simple polymorphism, which is a Factory method pattern. Basically, you create an interface class, say IA like so:

/* File: A.h */
#include <memory> /* For std::shared_ptr */
class IA;
/* Change the line below to boost::shared_ptr<> or
 * another implementation of a shared-pointer.
 * Read more:
 * http://en.wikipedia.org/wiki/Smart_pointer#shared_ptr_and_weak_ptr
 */
typedef std::shared_ptr<IA> APtr;

class IA {
public:
    static APtr Create(const int foo);
    IA(){}
    virtual ~IA(){}
    virtual void somePublicMethod() = 0;
};

In your A.cpp you'll have it's implementation:

/* File: A.cpp */
#include "A.h"

class A : public IA
{
public:
    A(const int foo):foo_(foo){}
    void somePublicMethod(){/* Your awesome implementation goes here */}
};

APtr IA::Create(const int foo)
{
    return APtr(new A(foo));
}

This way, you pass around only the interface and expose only the public methods to outside world, which the internals are in your CPP files.

Advantages:

  • Hide implementation completely from users

Disadvantages:

  • You'll need to create an interface for every class you intend to hide
  • Your users will have to call the factory method to create an instance. For e.g. Create() in the above example.
  • You will always have your class instances to be in heap memory than in stack, i.e., your implementation instances will always have to be a pointer. (Read More: Heap vs. Stack Memory)

Upvotes: 4

doctorlove
doctorlove

Reputation: 19232

If you don't need C operator()(A a) to be inline you could forward declare the parameter A as follows

class A;

Then you can move its definition to another header and include it in the places it's used.

Here are more details about forward declaration.

Upvotes: 2

Related Questions