我花了很多时间搜索有关此主题的信息,但我只能在碎片中找到它,因为大量的警告不使用多重继承而感到阴郁。
我对多重继承有多糟糕感兴趣。我对有效的用例也不感兴趣。我得到的信息是,你应该尽可能地避免它,并且几乎总有更好的选择。
但我想知道的是,在 你决定使用多重继承的时候,你是如何正确地做到的?
副主题我想更详细地解释一下:
并且,如果适用:
答案 0 :(得分:3)
采用以下层次结构:
A
B
,C
和E
继承自A
D
继承了B
和C
F
继承自D
和E
在代码中说:
class A { public: int a; }
class B : public A { }
class C : public A { }
class D : public B, public C { }
class E : public A { }
class F : public D, public E { }
或图表:
A A A
| | |
| | |
B C E
\ / /
\ / /
D /
\ /
F
通过这种结构,每个B,C和E都拥有自己的A副本。接下来,D持有B和C的副本,F持有D和E的副本。
这会导致问题:
D d;
d.a = 10; // ERROR! B::a or C::a?
对于这种情况,您使用虚拟继承,创建一个"钻石":
A A
/ \ |
/ \ |
B C E
\ / /
\ / /
D /
\ /
F
或代码:
class A { public: int a; }
class B : public virtual A { }
class C : public virtual A { }
class D : public B, public C { }
class E : public A { }
class F : public D, public E { }
现在你解决了上一个问题,因为B::a
和C::a
共享相同的内存,但同样的问题仍然存在,在另一个层面:
F f;
f.a = 10; // ERROR: D::a or E::a ?
这部分我不确定 Confirmed:您可以使用A for E的virtual
继承来解决此问题。但我会保持原样,以回答另一点:混合虚拟和非虚拟继承。
但请注意,您希望来自E::a
的{{1}}具有来自同一F
的不同D::a
值。为此,您必须输入您的F
:
F
现在,您的F *f = new F;
(static_cast<D*>(f))->a = 10;
(static_cast<E*>(f))->a = 20;
拥有两个不同的F* f
值。
从以上示例中学习这些课程:
A::a
可以绘制以下内存图:
对于A类:
class A { public: int a; }
class B : public virtual A { }
class C : public virtual A { }
class D : public B, public C { }
class E : public A { }
class F : public D, public E { }
对于B,C和E类:
+---------+
| A |
+---------+
意味着对于您创建的B,C和E的每个实例,您将创建另一个A实例。
对于D类,事情有点复杂:
+---------+
| B |
+---------+
|
V
+---------+
| A |
+---------+
这意味着当您创建D时,您有一个B实例和一个C实例。但是不是为每个B和C创建一个新的A实例,而是为这两个实例创建一个实例。
对于F:
+---------------------------------------+
| D |
+---------------------------------------+
| |
V V
+--------------+ +--------------+
| B | | C |
+--------------+ +--------------|
| |
V V
+---------------------------------------+
| A |
+---------------------------------------+
这意味着当你创建一个F时,你有:D的一个实例和E的一个实例。由于E实际上并不从A继承,所以在创建E时会创建一个新的A实例。
参加以下课程:
+-------------------------------------------------------+
| F |
+-------------------------------------------------------+
| |
V V
+---------------------------------------+ +---------+
| D | | E |
+---------------------------------------+ +---------+
| | |
V V |
+--------------+ +--------------+ |
| B | | C | |
+--------------+ +--------------+ |
| | |
V V V
+---------------------------------------+ +---------+
| A | | A |
+---------------------------------------+ +---------+
class A { virtual void f() = 0; }
class B : public A { virtual void f(int value) { std::cout << "bar" << value; } }
class C : public B { virtual void f() { std::cout << "foo"; f(42); } }
被称为A
(有些也称为abstract
),因为有纯虚函数。
interface
也是B
,因为它继承自abstract
并且不会覆盖A
方法,这是纯虚拟的,甚至可以定义自己的方法({{ 1}})
A::f(void)
是B::f(int)
的{{1}},因为它确定了将C
转换为&#34;完整&#34}所需的所有功能。 class - 覆盖implementation
。
这个答案并不完整,但它给出了一个大致的想法。