2010-06-15 126 views
5

我想阻止一个类能够将其'this'指针转换为其接口之一的指针。我通过使用中间代理类的私有继承来实现此目的。问题是我发现私有继承使所有基类的公共静态成员和类型都无法访问层次结构中继承类的所有类。C++私有继承和静态成员/类型

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! 
    } 
}; 

我已经在VS2008(所需版本)和VS2010中都试过这个,都没有工作。

任何人都可以想到一个解决方法吗?或者停止转换的另一种方法?

此外,我是行为的好奇心,它只是编译器实现的副作用,还是它的设计?如果通过设计,那么为什么?我一直认为私有继承意味着没有人知道从基地继承中间。然而,所展示的行为意味着私有继承意味着更多,实际上,Child没有比任何名称空间更少的对Base的访问权限!

+0

+1:的确是一个非常有趣的问题。 – 2010-06-15 18:15:23

回答

6

您应该能够通过完全限定其访问Base::Enum

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

这是由语言(C++ 03§11.2/ 3)规定的行为:

注意:私有基类的成员可能无法作为继承的成员名称访问,但可以直接访问。

接下来是一个扩展示例,它与您的示例代码非常相似。

但是,看起来Visual C++ 2008和Visual C++ 2010都无法正确实现这个功能,所以虽然可以使用::Base::Enum类型,但仍然无法访问::Base::value。 (实际上,Visual C++似乎得到了很多错误,因为它错误地允许你使用不完全合格的Base::Enum)。

要“避开”的问题,你可以使用声明添加到Middle类:

class Middle : private Base 
{ 
protected: 

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

这不会让你在Child类使用Base::EnumBase::value,但它可以让你使用EnumvalueMiddle::EnumMiddle::value

+1

我提交了关于Microsoft Visual的Visual C++错误的错误报告:https://connect.microsoft.com/VisualStudio/feedback/details/567693/ – 2010-06-16 03:37:39

+0

感谢您的详细解答。讨厌它是由一个错误引起的。不幸的是,在我的现实世界中,添加对Middle类的使用不是一种选择,因为Middle是一个将基类作为Type参数的模板化类。我唯一的选择是将枚举移出界面。 – WearyMonkey 2010-06-17 02:22:55

+0

我会注意到,我引用的标准中的“注释”实际上没有指定任何内容,只是解释了这种行为。我的猜测是,这种行为的实际规范通过描述名称解析如何发生的各个部分进行传播。 – 2010-06-18 01:43:00

1

我只有一个问题:你为什么私有继承?

继承是很破的概念,在我看来,因为它违反了一个责任原则:

  • 你继承接口
  • 你继承

不幸的是需要继承的实现对于面向对象代码中的多态性,所以在这种情况下你不能回避它。

但是,在这里你明确地希望不要使用多态,所以我发现自己想知道为什么使用继承,因为它是它唯一有趣的用法(imo)。

相反,在C++中,你可以使用:

  • 组成,代码重用
  • 免费功能(在自己的空间中定义的)
  • usingtypedef等..从带来的对象课外

你的例子似乎在这里受到限制,但我也把我的枚举包装到struct以防止名称空间污染千个符号(并且因为struct可以用作名称空间不能的模板参数)。

struct MyEnum 
{ 
    enum type 
    { 
    value 
    }; 
}; 

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

    Child(Enum e = MyEnum::value); 

private: 
}; 

我看不出什么毛病限定名称,而不是我觉得它可以更容易再次阅读,因为你知道我们是在谈论这枚举...

真的,private继承最好避免(通常用组合物代替)。唯一有效的情况(imo)是空基优化...坦率地说,它通常不是你需要的(像往常一样进行优化)。

+0

私有继承的其他用途是如果您需要访问受保护的类的成员。这不是一个理想的情况,但在极少数情况下会出现。我当然同意这是最好的避免。 – 2010-06-16 13:44:25

+0

我通常更喜欢在此处解耦:我创建一个公开继承并使用组合的中间类。 – 2010-06-16 14:44:15

+0

我当然同意在可能的情况下组合比继承更可取。然而,我现实世界中的基类是旧的大代码库中的核心类,做适当的重构工作意味着重写大部分代码。 – WearyMonkey 2010-06-17 02:26:24