2014-01-06 94 views
2

古怪继承情况:公开从基类继承,从派生的类私有继承

class Base 
{ 
public: 
    public virtual foo() = 0; 
}; 

class A : public Base 
{ 
public: 
    public virtual foo() override; 
protected: 
    int bar; 
}; 

class B : public A//something like 'public Base, protected A' 
{ 
public: 
    public virtual foo() override; 
}; 

基本上,可以B,从甲继承一切,但是只“看到”(且仅铸能够作为)基。基本上,我想用一堆的在B的功能,但希望B比语义不同:

B b; 
Base* valid_ptr = &b;//want this to be ok 
A* invalid_ptr = &b;//want this to be invalid 
A& invalid_ref = b;//want this to be super invalid 
A prevent(b);//want this to not be allowed to happen 
+0

反而的是?只是想到这个... – 2014-01-06 21:07:26

+0

当你尝试过它时发生了什么? –

+0

也许你可以传递'A'作为模板参数。 – 0x499602D2

回答

2

首先,你的代码编译仅当A派生自Base。如果基础是公开给大家,并且被保持的保护,唯一的办法就是不能承受群遍布A.

由于A没有到B visble到B的解决方案可以

class A: public Base 
{ ... }; 

class B: public Base 
{ 
    A a; 
public: 
    ... 
}; 

万一存在的Base 2个实例的成B(一个为B的基础上,其他同a构件推出)是不可接受的,另一种方式可以是通过虚拟碱去:

class A: 
    public virtual Base 
{ ... }; 

class B: 
    public virtual Base, 
    protected A 
{ ... }; 

这将使甲INV通过B(不能隐式地转换为A),但只有一个Base在A和B之间是公共的。

共享虚拟库的使用是所有情况下的常见习惯用法对象共享部分实现通过成员函数优势(所谓的“堆叠平行四边形不沉积”)或通过任意数量的接口(“钻石对象”)。

OOP纯化论者往往不喜欢这些数字,但这些都是正确的C++公民(即使没有找到其他经典OOP灵感设计语言的任何表示,由于多重继承失踪了!)

+0

嗯...好的答案,我没有考虑虚拟继承,因为使用它的开销。 – IdeaHat

+0

@MadScienceDreams我不确定你指的是什么,你在说什么开销? –

+0

它只需要一个指针...和双重间接(而不是简单的)虚拟呼叫。现代编译器有时会在链接过程中优化v-表,所以开销并不像1990年代大部分OOP书籍推荐的那样“可怕”。如果您打算使用虚函数,则您处于间接函数调用域中。在这一点上......完全使用它们! –

1

我认为你正在处理一个Composition vs Inheritance问题。

您可能必须从基B继承和使用合成技术来获得优势A的

否则,您列出的问题,你可能认为渲染构造人迹罕至的:

class A 
{ 
public: 
    A() {}; 

}; 

class B : private A 
{ 
public: 
    B() {}; 
}; 

例如(MSVC2012)

错误C2243: '类型转换':转换,从 'B *' 到 'A *' 存在,但 是人迹罕至

+0

我没有想到过载的构造函数/转换等,这可能很好地处理控制旋钮。(虽然工厂的东西总是让我感到混乱,但不确定实际有用物体的构造) – 2014-01-06 21:23:19

+0

但是B和A都来自Base?这不是要求吗? –

+0

如果用户发生**钻石问题**(http://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem),那是另一回事。在这种情况下,组成可能会有帮助 –