【问题标题】:Why Should I use virtual base classes?为什么我应该使用虚拟基类?
【发布时间】:2014-03-15 21:23:53
【问题描述】:

根据我的阅读,当您有一个包含数据的抽象基类时使用虚拟基类,因此不会复制该类,但是,如果您不使用虚拟类,复制该类有什么问题?

应该避免保存数据的抽象基类吗?

举个例子:

class Storable {
public:
  Storable(const string& s);
  virtual void read() = 0;
  virtual void write() = 0;
  virtual ~Storable();
protected:
  string file_name; // store in file named s
  Storable(const Storable&) = delete;
  Storable& operator=(const Storable&) = delete;
};

class Transmitter : public virtual Storable {
public:
  void write() override;
  // ...
};

class Receiver : public virtual Storable {
public:
  void write() override;
 // ...
};

class Radio : public Transmitter, public Receiver {
public:
  void write() override;
  // ...
};

这个例子取自《The C++ Programming Language》一书 第 4 版 - Bjarne Stroustrup。

【问题讨论】:

  • 我写重复类的时候,不是这个意义上的,我不会重复代码。
  • 问题是您可能希望两个实例的数据相同,这变得难以维护
  • 看看钻石继承,例如here.
  • 刻薄但基于经验的答案是从不,因为你不应该使用虚拟继承。如果您处于虚拟继承似乎完全必要的情况,那么您可能应该深入重新考虑您的类结构。如果您的两个基类需要一组通用的功能或数据,请改用聚合和依赖注入。

标签: c++ oop inheritance c++11 abstract-class


【解决方案1】:

为了简短起见,如果您不对Storable 使用虚拟继承,那么Radio 将继承它两次,一次来自Transmitter,一次来自Receiver

这意味着Radio 需要用于Storable 的2 个实例的内存,这是一些内存开销,并且您很可能希望两者都具有相同的数据(如果您实际上不继承它,则必须手动管理)。
此外,当您从Storable(或访问数据成员)调用基类函数时,您要调用哪一个?来自Storable 的一个通过Transmitter 继承,或者来自Storable 的一个通过Receiver 继承

虚拟继承只需要一个Storable 基类实例,所有继承的类都共享一个实例。

有关虚拟基类的更多信息,这里有一个很好的问题:In C++, what is a virtual base class?

【讨论】:

  • 那么,每次我使用抽象基类时,我应该使用虚拟继承吗?
  • @Alex 只有当它被继承两次时才会出现问题,比如T2T3继承自T1T4继承自T2T3
  • 如果您只继承T1 的单个实例,那么就不需要虚拟基类。
  • @Alex:设计问题是共享基的立即派生类需要声明虚拟继承,但它是最派生的 i> 知道它是否会以需要虚拟继承以避免重复的方式使用多重继承的类。因此,如果您希望您的类Transmitter 以这种方式支持在多重继承中的使用(或者您认为可能),那么可以,虚拟继承。但通常在实践中你并没有怀疑,你不想支持它:-)
【解决方案2】:

虚拟基类用于虚拟继承,是一种在使用多重继承时防止给定类的多个“实例”出现在继承层次结构中的方法,即只是为了避免DIAMOND PROBLEM。为了避免这个菱形问题,我们要么使用虚拟基类,要么使用'::',即​​范围解析运算符,以便清楚地了解我们想要使用什么类的方法或数据。 请参考Diamond Problem

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-01
    • 2019-12-26
    • 2023-04-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-15
    • 2010-09-22
    相关资源
    最近更新 更多