C++之虚函数与虚继承详解

本文详细探讨了C++中的虚继承和虚函数,解释了它们如何解决多重继承的问题,包括存储空间浪费和二义性。通过介绍虚基类指针和虚基类表,阐述了虚继承的实现原理,同时对比了虚函数的实现。文章还补充了虚继承的额外知识点,并通过四个测试案例展示了不同情况下的继承行为。
摘要由CSDN通过智能技术生成

虚继承和虚函数是完全无相关的两个概念。

虚继承是解决C++多重继承问题的一种手段,从不同途径继承来的同一基类,会在子类中存在多份拷贝。这将存在两个问题:

其一,浪费存储空间;

第二,存在二义性问题,通常可以将派生类对象的地址赋值给基类对象,实现的具体方式是,将基类指针指向继承类(继承类有基类的拷贝)中的基类对象的地址,但是多重继承可能存在一个基类的多份拷贝,这就出现了二义性。

虚继承可以解决多种继承前面提到的两个问题:

虚继承底层实现原理与编译器相关,一般通过虚基类指针和虚基类表实现,每个虚继承的子类都有一个虚基类指针(占用一个指针的存储空间,4字节)和虚基类表(不占用类对象的存储空间)(需要强调的是,虚基类依旧会在子类里面存在拷贝,只是仅仅最多存在一份而已,并不是不在子类里面了);当虚继承的子类被当做父类继承时,虚基类指针也会被继承。

实际上,vbptr指的是虚基类表指针(virtual base table pointer),该指针指向了一个虚基类表(virtual table),虚表中记录了虚基类与本类的偏移地址;通过偏移地址,这样就找到了虚基类成员,而虚继承也不用像普通多继承那样维持着公共基类(虚基类)的两份同样的拷贝,节省了存储空间。

在这里我们可以对比虚函数的实现原理:他们有相似之处,都利用了虚指针(均占用类的存储空间)和虚表(均不占用类的存储空间)。

虚基类依旧存在继承类中,只占用存储空间;虚函数不占用存储空间。

虚基类表存储的是虚基类相对直接继承类的偏移;而虚函数表存储的是虚函数地址。

补充:

1、D继承了B,C也就继承了两个虚基类指针

2、虚基类表存储的是,虚基类相对直接继承类的偏移(D并非是虚基类的直接继承类,B,C才是)

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

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

#if 0

//测试虚表的存在

#include <iostream>

using namespace std;

class A

{

    int i = 10;

    int ia = 100;

    void func() {}

    virtual void run() { cout << "A::run()" << endl; }

    virtual void run1() { cout << "A::run1()" << endl; }

    virtual void run2() { cout << "A::run2()" << endl; }

};

class B : public A

{

    virtual void run() { cout << "B::run()" << endl; }

    virtual void run1() { cout << "B::run1()" << endl; }

};

class C :public A

{

    virtual void run() { cout << "C::run()" << endl; }

    virtual void run1() { cout << "C::run1()" << endl; }

    virtual void run3() { cout << "C::run3()" << endl; }

};

class D :/*virtual*/ public A

{

    virtual void run() { cout << "D::run()" << endl; }

    virtual void run1() { cout << "D::run1()" << endl; }

    virtual void run2() { cout << "D::run2()" << endl; }

    virtual void run3() { cout << "D::run3()" << endl; }

};

int test()

{

    cout << sizeof(A) << endl

        << sizeof(B) << endl

        << sizeof(C) << endl

        << 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是纠结伦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值