views:

109

answers:

2

I am trying to stop a class from being able to convert its 'this' pointer into a pointer of one of its interfaces. I do this by using private inheritance via a middle proxy class. The problem is that I find private inheritance makes all public static members and types of the base class inaccessible to all classes under the inheriting class in the hierarchy.

class Base
{
public:
    enum Enum
    {
        value
    };
};

class Middle : private Base
{ 
};

class Child : public Middle
{
public:
    void Method()
    {
        Base::Enum e = Base::value; // doesn't compile BAD!     
        Base* base = this; // doesn't compile GOOD!
    }
};

I've tried this in both VS2008 (the required version) and VS2010, neither work.

Can anyone think of a workaround? Or a different approach to stopping the conversion?

Also I am curios of the behavior, is it just a side effect of the compiler implementation, or is it by design? If by design, then why? I always thought of private inheritance to mean that nobody knows Middle inherits from Base. However, the exhibited behavior implies private inheritance means a lot more than that, in-fact Child has less access to Base than any namespace not in the class hierarchy!

+5  A: 

You should be able to access Base::Enum by fully qualifying it:

class Child : public Middle
{
public:
    void Method()
    {
        ::Base::Enum e = ::Base::value;
    }
};

This is the behavior specified by the language (C++03 §11.2/3):

Note: A member of a private base class might be inaccessible as an inherited member name, but accessible directly.

This is followed by an extended example that is effectively similar to your example code.

However, it appears that neither Visual C++ 2008 nor Visual C++ 2010 correctly implements this, so while you can use the type ::Base::Enum, you still can't access ::Base::value. (Actually, Visual C++ seems to have gotten a lot of this wrong, as it incorrectly allows you to use the not-fully-qualified Base::Enum).

To "get around" the problem, you can add using declarations to the Middle class:

class Middle : private Base
{ 
protected:

    using Base::Enum;
    using Base::value;
};

This won't let you use Base::Enum or Base::value in your Child class, but it will allow you to use an Enum and value or Middle::Enum and Middle::value.

James McNellis
I submitted a bug report on Microsoft Connect concerning the Visual C++ bugs: https://connect.microsoft.com/VisualStudio/feedback/details/567693/
James McNellis
Thanks for your detailed answer. Annoying it's caused by a bug. Unfortunately adding using to the Middle class is not an option in my real world case, as Middle is a templated class that takes the base class as a Type argument. My only option is to move the enum outside of the interface.
WearyMonkey
I'll note that the "note" from the standard that I quoted really doesn't specify anything, it just explains this behavior. My guess is that the actual specification of this behavior is spread through the various sections describing how name resolution takes place.
James McNellis
+1  A: 

I only have one question: why you private inheritance at all ?

Inheritance is quite a broken concept, in my opinion, because it violates the One Responsibility principle:

  • you inherit the interface
  • you inherit the implementation

Unfortunately inheritance is required for polymorphism in Object-Oriented code, so you can't shy away from it in this case.

But here you explicitly wish NOT to use polymorphism, so I find myself wondering why using inheritance at all, since it's its sole interesting use (imo).

Instead, in C++, you can use:

  • Composition, for code reuse
  • Free functions (defined in their own namespace)
  • using, typedef etc... to bring objects from outside the class

Your example seems constrained here, but I too wrap my enums into struct to prevent namespace pollution by a thousand symbols (and because struct can be used as template parameters wheres namespaces cannot).

struct MyEnum
{
  enum type
  {
    value
  };
};

class Child
{
public:
  typedef MyEnum::type Enum;

  Child(Enum e = MyEnum::value);

private:
};

I don't see anything wrong with qualifying the name, instead I feel it makes it easier to read again, since you know which enum we are talking about...

Really, private inheritance is best avoided (and usually replaced by Composition). The only valid case (imo) is for Empty Base Optimization... and frankly it's not often you need it (as usual with optimizations).

Matthieu M.
The other use for private inheritance is if you need access to protected members of a class. That's not an ideal situation, but it comes up on rare occasions. I certainly agree it's best avoided.
James McNellis
I usually prefer to decouple at this point: I create a middle class that inherits publicly and use composition.
Matthieu M.
I certainly agree that composition is preferable to inheritance where possible. However the base class in my real world problem is core class in an old large code base, doing a proper refactor job would mean rewriting most of the code.
WearyMonkey