带有虚函数的情况。

下面情况编译器也会在需要的时候为其合成。

1.如果一个类自己声明为虚函数.

 1 #include<iostream>
2 using namespace std;
3 class Base
4 {
5 public:
6 virtual void foo(){}
7 };
8 int main()
9 {
10 Base b;
11 while (1);
12 return 0;
13 }

分析:由于类中声明了虚函数,所以编译器会为其合成一个出来,这个合成的默认构造函数的作用是用来保存虚函数表的指针。

2.如果一个类继承了带虚函数的类。

1)单继承情况

 1 #include<iostream>
2 using namespace std;
3 class Base
4 {
5 public:
6 virtual void foo(){}
7 };
8 class Deprive:public Base
9 {
10 public:
11 void foo() override {
12
13 }
14 };
15 int main()
16 {
17 Deprive d;
18 while (1);
19 return 0;
20 }

分析:由于继承关系,所以类Base的虚函数属性也被Deprive继承下来,由于类Deprive中没有自己的构造函数,所以此时编译器会为其合成一个出来,同样,在这个合成的默认构造函数中,所做的工作是保存虚函数表的指针。(这里通过sizeof(Deprive)可以看出,类的大小还是4。也就是说,类Base和类Deprive共用了一个虚函数表指针).

2)多继承情况

 1 #include<iostream>
2 using namespace std;
3 class Base1
4 {
5 public:
6 virtual void foo1(){}
7 virtual void foo1(){}
8 };
9 class Base2
10 {
11 public:
12 virtual void func1(){}
13 virtual void func2(){}
14 };
15 class Deprive:public Base1,public Base2
16 {
17 public:
18 void foo1() override {}
19 void func2()override {}
20 virtual void My_HanShu(){}
21 };
22 int main()
23 {
24 Deprive d;
25 while (1);
26 return 0;
27 }

分析:同样,在多继承体系中,编译器会为类Deprive合成一个默认的构造函数出来,用来保存虚函数表的地址,这里通过sizeof(Deprive)可以看出大小为8字节,所以在默认的构造函数中有两个虚函数表指针,一个是与基类共用的,另一个是另外一个基类的。

注:多继承时,按照继承的顺序,子类的虚函数表指针与第一个继承的父类共用。

3.类派生自一个继承链串。

 1 #include<iostream>
2 using namespace std;
3 class Base1
4 {
5 public:
6 virtual void foo1(){}
7 };
8 class Base2:public Base1
9 {
10 public:
11 };
12 class Deprive:public Base2
13 {
14 public:
15 };
16 int main()
17 {
18 Deprive d;
19 while (1);
20 return 0;
21 }

分析:这种情况本质没有什么区别,只要基类有虚函数在,那么不管他的派生类的链串有多长,虚函数的属性就会被继承,虚函数属性被继承了,接下来的分析就和前面相同了。

下面是C++对象模型中的例子(我添加了一些代码以便运行的效果):(书P45页)

 1 #include<iostream>
2 using namespace std;
3 class Widget
4 {
5 public:
6 virtual void flip()=0;
7 };
8 void flip(Widget& widget)
9 {
10 widget.flip();
11 }
12 class Bell:public Widget
13 {
14 public:
15 void flip()
16 {
17 cout << "Bell" << endl;
18 }
19 };
20 class Whistle:public Widget
21 {
22 public:
23 void flip()
24 {
25 cout << "Whistle" << endl;
26 }
27 };
28 void foo()
29 {
30 Bell b;
31 Whistle w;
32 flip(b);
33 flip(w);
34 }
35 int main()
36 {
37 foo();
38 while (1);
39 return 0;
40 }

分析:由于编译器在合成的默认构造函数中添加了虚函数表指针,所以接下来在函数void flip(Widget& widget)中的调用是通过虚函数表走的。

widget.flip()的编译器视角就是:*widget.vptr[1](&widget)  (关于布局写法以后再深谈)。

最新文章

  1. 你所不知道的linq
  2. WPS 表格筛选两列相同数据
  3. HackerRank training-the-army
  4. MySQL- 锁(2)
  5. NFS挂载根文件系统
  6. POJ 1743 Musical Theme 后缀数组 最长重复不相交子串
  7. 更换用installshield打包生成exe文件的图标【转】
  8. aggregations 详解1(概述)
  9. Visual Studio 2015中的常用调试技巧分享
  10. bat文件的妙用1-一键开启所有开发软件
  11. JBPM4.4GPD设计器中文乱码问题的另一种解决方法
  12. Hibernat之关系的处理一对多/多对一
  13. PHP导出一个txt文本文件
  14. Winsock网络编程笔记(4)----基本的理论知识
  15. 移动应用开发技术选型:WebApp&gt;HybridApp&gt;NativeApp
  16. vue安装搭建
  17. JS本地存储信息的实现方式(localStorage 与 userData)
  18. iphone6/6+ 适配心得
  19. [bzoj1571][Usaco2009 Open]滑雪课Ski
  20. IE版本检测

热门文章

  1. c++11之all_of 、 any_of 和 none_of 的用法
  2. 【LeetCode】11. Container With Most Water 盛最多水的容器
  3. 【LeetCode】341. Flatten Nested List Iterator 解题报告(Python&C++)
  4. 【LeetCode】814. Binary Tree Pruning 解题报告(Python & C++)
  5. Another kind of Fibonacci(hdu3306)
  6. wordpress中遇到的问题
  7. 洛谷1052——过河(DP+状态压缩)
  8. 【C\C++笔记】指针输出字符串
  9. 源码分析 SpringCloud 2020.0.4 版本 EurekaClient 的注册过程
  10. 【2021/12/31】uniapp之安卓原生插件开发教程