3

This is a question that troubles me a for a while, but could not find a the best way to deal with it. I am trying to show this through an example.

I am developing a graphics library with many classes. Some of the classes are "part of" relationship with each other, like these 3 classes:

namespace MyGraphicsLibrary
{

class MatrixStack
{

};

class Transform
{
    MatrixStack mMatrixStack;
};

class Renderer
{
    Transform mTransform;
};

}

The Renderer class is for users to use, but i did not want them to see Transform, MatrixStack classes when they lookup the MyGraphicsLibrary. The last two classes are only for Renderer class and not for users to use.

Here i am trying to do two things:

  1. Hiding the Transform, MatrixStack classes from users.

  2. Reflect the "part-of" hierarchy of the classes.

I tried the followings to solve this:

  1. The best solution for me would be the private nested-classes, as it would show the user that the nested class is private and also reflects the hierarchy if you simply look at the Renderer class declaration. The following post actually makes me uncertain that is good solution: Pros and cons of using nested C++ classes and enumerations?

  2. I tried to put Transform, MatrixStack into another namespace called Private. So user looking up MyGraphicsLibrary namespace would see Private namespace only covering all classes which are not for the users. That's good, but there are lot of other classes with the same issue, and i quickly fill the Private namespace with classes which has nothing to do with each other. Here I could only come up with ugly solutions, like introducing nested namespaces:

    namespace MyGraphicsLibrary
    {
        //private classes belonging to Renderer class
        namespace PrivateRenderer
        {
        class MatrixStack
        {
        };
    
            class Transform
            {
                MatrixStack mMatrixStack;
            };
        }
    
        //public classes for users
        class Renderer
        {
        Transform mTransform;
        };
    }
    

Maybe I miss something here, but what do you think which one is the way to go. Does anybody has a 3rd way?

Community
  • 1
  • 1
Avi
  • 1,066
  • 1
  • 15
  • 37

3 Answers3

2

you can use the PIMPL- (also called opaque pointer) idiom. with hat you can entirely hide the classes from user the following way:

In your public header (in your include folder): Renderer.h

class RendererImpl; // forward declaration of internal render structure

//public classes for users
class Renderer
{
  public:
    Renderer();
    ~Renderer();
    // public interface comes here and delegates all calls to RendererImpl (have to be implemented in cpp)

  RendererImpl* renderer; // better use something like QScopedPointer here
};

the cpp:

#include "RendererImpl.h" // your actual renderer that 

Renderer::Renderer()
:renderer(new RendererImpl)
{}
Renderer::~Renderer()
{
  delete renderer;
}

The implementations may be completely hidden from the API. The headers have to be separated from the real interfaces.

vlad_tepesch
  • 6,681
  • 1
  • 38
  • 80
1

If you want to store Transform as a plain (non-pointer/reference) member, then for the compilation of your public header, its definition should also be visible, because it affects the layout of the container class.

Consequently, the type will be visible wherever you want to use the container class.

You have the following options:

  1. Signal that they are not for public use through naming. Either by putting into a namespace (like detail in boost), or prefixing/suffixing its name.
  2. Use a technique that prevents clients from using that class. Make every member functions private and declare the container class friend. The attorney-client idiom is a more sophisticated way of fine-grained access control.
  3. Store Transform indirectly (pointer or reference), so you do not need its definition in the public header. This is pimpl. A variant of this if the public type is an interface, a base class of the actual Transform implementation.

Unnamed namespace: definitely a bad idea in a header. Unnamed namespaces are like C static: they get a compiler-generated identifier that is guaranteed to be unique to the given translation unit. You will end up with as many distinct Transform types as many places you included its definition.

jmihalicza
  • 2,083
  • 12
  • 20
  • Thank you, i mark this as answer as it offers more choices. I read about pimpl earlier, but it seems i have to dig into it more then. – Avi May 06 '13 at 15:15
0

Use an anonymous namespace:

namespace MyGraphicsLibrary
{
    namespace
    {
        class MatrixStack
        {

        };

        class Transform
        {
            MatrixStack mMatrixStack;
        };
    }

    class Renderer
    {
        Transform mTransform;
    };

}
nullptr
  • 2,244
  • 1
  • 15
  • 22