2012-07-02 52 views
1

在C++中,如果我有一个类Base,它是一个私有基类DerivedBase没有虚函数,它会更干净,而不是替代继承与封装类Encapsulate?我想在这种情况下继承的唯一好处是可以直接在派生类中访问基类,而不是通过memberVariable。其中一种或其他做法是否被认为更好,还是更多是个人风格问题?在没有虚拟时应该使用私有继承吗?

class Base { 
    public: 
    void privateWork(); 
    // No virtual member functions here. 
}; 

class Derived : Base { 
    public: 
    void doSomething() { 
     privateWork(); 
    } 
}; 

class Encapsulate { 
    Base memberVariable; 

    public: 
    void doSomething() { 
     memberVariable.privateWork() 
    } 
}; 
+2

将GoF设计模式抛出窗口,并开始编码... :) – Gigi

+0

难道你不应该有至少一个虚拟析构函数吗? –

+0

@LuchianGrigore:如果继承是私有的,那么无论如何您都无法通过基指针销毁派生。所以我会说不一定。 –

回答

2

请记住,继承模型“Liskov替换”:Foo是一个Bar当且仅当您可以将Foo变量传递给期望Bar的每个函数。私有继承不会对此进行建模。它的模型组合(Foo是以Bar的形式实现的)。

现在,你应该几乎总是使用第二个版本,因为它更简单并且更好地表达意图:对于不了解它的人来说,它不那么令人困惑。

但是,有时候,私有继承是很方便的:

class FooCollection : std::vector<Foo> 
{ 
public: 
    FooCollection(size_t n) : std::vector<Foo>(n) {}; 

    using std::vector<Foo>::begin; 
    using std::vector<Foo>::end; 
    using std::vector<Foo>::operator[]; 
}; 

这样就可以重用一些的vector的功能,而无需手动转发开始的,结束了2个版本(常量+非常量)和operator[]

在这种情况下,您根本没有多态:这不是继承,这是构图伪装;您无法使用FooCollection作为向量。特别是,你不需要虚拟析构函数。

2

如果没有virtual功能,那么继承不应OO使用。请注意,这并不意味着它不能被使用,有一些(有限)的情况,你可能需要(ab)将继承用于OO之外的其他目的。

+0

有时候,私人继承对于“相信我的关系”而言是很好的。 –

+0

@MarkB:继承是最受滥用的功能。作为一般的经验法则,继承是关于代码重用的,但与大多数人认为的方向相反:应该使用继承,以便与您的基础一起工作的代码将与您的新类型一起工作(而不是滥用继承来重用该功能在你的基地)。不应该派生一个没有虚函数的类(手挥手:即假设没有静态多态):使用'Base'对象的现有代码将无法通过获取'Derived'引用来做新事情 –

+0

@MarkB:考虑一个具有计时器类的框架,您可以在该计时器类上注册以进行通知。该框架需要一个特定的接口来注册定时器,(比如'Notifiable')。现在考虑您要在您的应用程序中提供一个定期计时器,其中使用的确切框架只是一个实现细节。然后你将使用私有继承来“实现”,即:从客户的角度来看,你的类不是“Notifiable”的实例,但是在内部,这就是你实现的方式。 –