C++构造函数语义学(二)(基于C++对象模型)
2024-10-19 21:39:22
带有虚函数的情况。
下面情况编译器也会在需要的时候为其合成。
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) (关于布局写法以后再深谈)。
最新文章
- 你所不知道的linq
- WPS 表格筛选两列相同数据
- HackerRank training-the-army
- MySQL- 锁(2)
- NFS挂载根文件系统
- POJ 1743 Musical Theme 后缀数组 最长重复不相交子串
- 更换用installshield打包生成exe文件的图标【转】
- aggregations 详解1(概述)
- Visual Studio 2015中的常用调试技巧分享
- bat文件的妙用1-一键开启所有开发软件
- JBPM4.4GPD设计器中文乱码问题的另一种解决方法
- Hibernat之关系的处理一对多/多对一
- PHP导出一个txt文本文件
- Winsock网络编程笔记(4)----基本的理论知识
- 移动应用开发技术选型:WebApp>;HybridApp>;NativeApp
- vue安装搭建
- JS本地存储信息的实现方式(localStorage 与 userData)
- iphone6/6+ 适配心得
- [bzoj1571][Usaco2009 Open]滑雪课Ski
- IE版本检测
热门文章
- c++11之all_of 、 any_of 和 none_of 的用法
- 【LeetCode】11. Container With Most Water 盛最多水的容器
- 【LeetCode】341. Flatten Nested List Iterator 解题报告(Python&C++)
- 【LeetCode】814. Binary Tree Pruning 解题报告(Python & C++)
- Another kind of Fibonacci(hdu3306)
- wordpress中遇到的问题
- 洛谷1052——过河(DP+状态压缩)
- 【C\C++笔记】指针输出字符串
- 源码分析 SpringCloud 2020.0.4 版本 EurekaClient 的注册过程
- 【2021/12/31】uniapp之安卓原生插件开发教程