虚基类数据成员

时间:2009-07-28 10:03:28

标签: c++ inheritance virtual

为什么建议不要在虚拟基类中使用数据成员?

功能成员怎么样? 如果我有一个对所有派生类都通用的任务,那么虚拟基类可以执行任务,还是派生继承自两个类 - 从虚拟接口和执行任务的普通基类?

感谢。

5 个答案:

答案 0 :(得分:11)

作为一种实践,您应该只使用虚拟继承来定义接口,因为它们通常与多重继承一起使用,以确保派生类中只存在该类的一个版本。纯接口是多重继承的最安全形式。当然,如果您知道自己在做什么,可以根据需要使用多重继承,但如果不小心,可能会导致代码变弱。

虚拟继承的最大缺点是它们的构造函数是否接受参数。如果必须将参数传递给虚基类的构造函数,则强制所有派生类显式调用构造函数(它们不能依赖于调用构造函数的基类)。

我可以看到您明确建议的唯一原因是虚拟基类中的数据可能需要构造函数参数。

修改 在马丁的评论之后我做了一些家庭工作,感谢马林。第一行不太正确:

  

作为一种练习,你应该只使用   虚拟继承来定义   通常使用的接口   具有多重继承以确保   只有一个版本的类   出现在派生类中。

如果基类是纯接口,则虚拟继承没有区别(除了略有不同的编译器错误,在vc8中,如果未实现所有方法)。如果基类有数据,它只会产生真正的差别,在这种情况下,你最终得到的是钻石而不是U形

Non virtual    virtual
  A     A          A
  |     |        /   \
  B     C       B     C
   \   /         \   /
     D             D

在虚拟案例中,B和C共享相同的A副本。

但是我仍然同意纯接口是最安全的多重继承形式的所有其他内容,即使它们不需要虚拟继承。而且构造函数参数和虚拟继承都很痛苦。

答案 1 :(得分:2)

核心建议是在虚拟基础中使用默认构造函数。如果你不这样做,那么每个派生程度最高的类(即任何子类)必须明确地调用虚拟基础ctor,这会导致愤怒的同事敲你的办公室门......

class VirtualBase {
public:
    explicit VirtualBase( int i ) : m_i( i ) {}
    virtual ~VirtualBase() {}

private:
    int m_i;
};

class Derived : public virtual VirtualBase {
public:
    Derived() : VirtualBase( 0 ) {} // ok, this is to be expected
};

class DerivedDerived : public Derived { // no VirtualBase visible
public:
    DerivedDerived() : Derived() {} // ok? no: error: need to explicitly
                                    // call VirtualBase::VirtualBase!!
    DerivedDerived() : VirtualBase( 0 ), Derived() {} // ok
};

答案 2 :(得分:1)

我从未见过这个推荐。

一个类是一组密切相关的函数和数据。基类的目的是拥有一组可供派生类重用的公共函数和数据。

我认为限制自己在基类中没有数据成员或非纯虚函数会减少代码重用量,从长远来看会导致代码可靠性降低。

答案 3 :(得分:0)

a)成员应该是私有的 - 所以你可能会在派生类中使用它们时遇到问题(所以你必须添加getter和setter方法,这会炸毁你的界面)

b)不要声明你当前不使用的东西 - 仅在访问/使用它们的类中声明变量

c)虚拟基类应该只包含接口/虚拟方法,仅此而已

我希望这有点帮助,即使我的理由不完美和完整:)

侨, 克里斯

答案 4 :(得分:0)

用于在C ++中模拟接口的全部abtract基类不应该包含数据成员 - 因为它们描述的是接口,而实例状态是一个实现细节。

除此之外,包含虚函数的基类可能具有数据成员。但通常的规则适用:

  • 使它们尽可能隐藏,如果需要保留类不变量,则使用getter和setter (这里有一个漏洞:如果没有与该成员关联的不变量,即它可以在任何给定时间假定任何可能的值,您可以将其公之于众。但是,这会否定派生类添加不变量。
  • 继承设计:您的类的契约应该定义派生类的职责和可能性,它需要/可以覆盖什么目的。