我试图阻止一个类将其'this'指针转换为其某个接口的指针。我通过中间代理类使用私有继承来做到这一点。问题是我发现私有继承使得层次结构中继承类下的所有类都无法访问所有公共静态成员和基类类型。
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中都尝试过这种方法,但都没有。
任何人都可以想到一个解决方法吗?或者采用不同的方法来停止转换?
此外,我对这种行为感到好奇,它只是编译器实现的副作用,还是设计上的?如果按设计,那么为什么呢?我一直认为私有继承意味着没有人知道中继继承自Base。但是,所展示的行为意味着私有继承意味着更多,实际上,Child比不在类层次结构中的任何命名空间更少访问Base!
答案 0 :(得分: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;
};
这不允许您在Base::Enum
课程中使用Base::value
或Child
,但它允许您使用Enum
和value
或Middle::Enum
和Middle::value
。
答案 1 :(得分:1)
我只有一个问题:为什么你要私人继承?
在我看来,继承是一个非常破碎的概念,因为它违反了“一个责任”原则:
不幸的是,面向对象代码中的多态性需要继承,因此在这种情况下你不能回避它。
但是在这里你明确希望不使用多态,所以我发现自己想知道为什么要使用继承,因为它是唯一有趣的用途(imo)。
相反,在C ++中,您可以使用:
using
,typedef
等...来自课堂外的对象你的例子似乎受到限制,但我也将我的枚举包装到struct
中,以防止命名空间污染一千个符号(因为struct
可以用作模板参数,而名称空间不能)。
struct MyEnum
{
enum type
{
value
};
};
class Child
{
public:
typedef MyEnum::type Enum;
Child(Enum e = MyEnum::value);
private:
};
我没有看到对这个名字进行资格认定有什么问题,相反我认为这样可以让你更容易再次阅读,因为你知道我们在谈论哪个枚举...
实际上,最好避免private
继承(通常由Composition替换)。唯一有效的情况(imo)是针对空基优化的......坦白说,通常不需要它(像往常一样进行优化)。