非常感激我队友大爹给我的复习资料

为了解决多继承时的命名冲突和冗余数据问题,C++ 提出了虚继承,使得在派生类中只保留一份间接基类的成员。在继承方式前面加上 virtual 关键字就是虚继承。

必须在虚派生的真实需求出现前就已经完成虚派生的操作。在示例中,当定义 D 类时才出现了对虚派生的需求,但是如果 B 类和 C 类不是从 A 类虚派生得到的,那么 D 类还是会保留 A 类的两份成员。换个角度讲,虚派生只影响从指定了虚基类的派生类中进一步派生出来的类,它不会影响派生类本身。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/*
虚继承(Virtual Inheritance)
为了解决多继承时的命名冲突和冗余数据问题,C++ 提出了虚继承,使得在派生类中只保留一份间接基类的成员。
在继承方式前面加上 virtual 关键字就是虚继承
1. 必须在虚派生的真实需求出现前就已经完成虚派生的操作。在示例中,当定义 D 类时才出现了对虚派生的需求,
但是如果 B 类和 C 类不是从 A 类虚派生得到的,那么 D 类还是会保留 A 类的两份成员。换个角度讲,虚派生只影响
从指定了虚基类的派生类中进一步派生出来的类,它不会影响派生类本身。
*/

#include <iostream>
using namespace std;

// 间接基类A
class A {
protected:
int _a;
public:
void func() {
cout << "this is AAAA" << endl;
}
};

// 直接基类B
class B : virtual public A {
protected:
int _b;
};

// 直接基类C
class C : virtual public A {
protected:
int _c;
};

class D : public B, public C {
public:
void setA(int a) {_a = a;}
void setB(int b) {_b = b;}
void setC(int c) {_c = c;}
};

int main(void){
D d;
d.setA(5);
d.func();
return 0;
}

/*
==================
this is AAAA
==================
*/

构造函数

如果虚基类声明有非默认形式的(即带形参的)构造函数, 并且没有声明默认形式的构造函数, 这时, 在整个继承关系中, 直接或间接继承虚基类的所有派生类, 都必须在构造函数的成员初始化列表中列出对虚基类的初始化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
using namespace std;

class Base0{
public:
int var0;
Base0(int var) : var0(var) {}
void fun0() { cout << "Member of Base0" << endl; }
};

class Base1 : virtual public Base0{
public:
int var1;
Base1(int var) : Base0(var) {}
};

class Base2 : virtual public Base0{
public:
int var2;
Base2(int var) : Base0(var) {}
};

int main(void){
Base1 b(1);
b.fun0();
return 0;
}