C++构造函数语义学(二)(基于C++对象模型)
带有虚函数的情况。
下面情况编译器也会在需要的时候为其合成。
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) (关于布局写法以后再深谈)。
C++构造函数语义学(二)(基于C++对象模型)的更多相关文章
- C++构造函数语义学(一)(基于C++对象模型)
如果一个类没有自己的构造函数,编译器会在需要的时候为其合成一个出来,俗称:合成默认构造函数.但是请注意是在需要的时候,并不是所有情况. 请看下面代码: 1 #include<iostream&g ...
- C++构造函数语义学(三)(基于C++对象模型)
带有虚基类的情况. 1 #include<iostream> 2 using namespace std; 3 class X 4 { 5 public: 6 int i; 7 }; 8 ...
- 构造函数语义学之Copy Constructor构建操作(2)
二.详述条件 3 和 4 那么好,我又要问大家了,条件1 和 2比较容易理解.因为member object或 base class 含有copy constructor.那么member objec ...
- VSTO学习笔记(二)Excel对象模型
原文:VSTO学习笔记(二)Excel对象模型 上一次主要学习了VSTO的发展历史及其历代版本的新特性,概述了VSTO对开发人员的帮助和效率提升.从这次开始,将从VSTO 4.0开始,逐一探讨VSTO ...
- 构造函数语义学——Copy Constructor 篇
构造函数语义学--Copy Constructor 篇 本文主要介绍<深度探索 C++对象模型>之<构造函数语义学>中的 Copy Constructor 构造函数的调用时机 ...
- CRL快速开发框架系列教程二(基于Lambda表达式查询)
本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...
- Android消息推送(二)--基于MQTT协议实现的推送功能
国内的Android设备,不能稳定的使用Google GCM(Google Cloud Messageing)消息推送服务. 1. 国内的Android设备,基本上从操作系统底层开始就去掉了Googl ...
- word2vec原理(二) 基于Hierarchical Softmax的模型
word2vec原理(一) CBOW与Skip-Gram模型基础 word2vec原理(二) 基于Hierarchical Softmax的模型 word2vec原理(三) 基于Negative Sa ...
- 构造函数语义学——Default Constructor篇
构造函数语义学--Default Constructor 篇 这一章原书主要分析了:编译器关于对象构造过程的干涉,即在对象构造这个过程中,编译器到底在背后做了什么 这一章的重点在于 default c ...
随机推荐
- 【转】最小生成树——Kruskal算法
[转]最小生成树--Kruskal算法 标签(空格分隔): 算法 本文是转载,原文在最小生成树-Prim算法和Kruskal算法,因为复试的时候只用到Kruskal算法即可,故这里不再涉及Prim算法 ...
- 【九度OJ】题目1190:大整数排序 解题报告
[九度OJ]题目1190:大整数排序 解题报告 标签(空格分隔): 九度OJ 原题地址:http://ac.jobdu.com/problem.php?pid=1190 题目描述: 对N个长度最长可达 ...
- 【LeetCode】978. Longest Turbulent Subarray 解题报告(C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 虫取法 日期 题目地址:https://leetco ...
- 【九度OJ】题目1180:对称矩阵 解题报告
[九度OJ]题目1180:对称矩阵 解题报告 标签(空格分隔): 九度OJ http://ac.jobdu.com/problem.php?pid=1180 题目描述: 输入一个N维矩阵,判断是否对称 ...
- 【LeetCode】150. Evaluate Reverse Polish Notation 解题报告(Python)
[LeetCode]150. Evaluate Reverse Polish Notation 解题报告(Python) 标签: LeetCode 题目地址:https://leetcode.com/ ...
- Redis -使用 Bitmap
redis数据类型 String.Set.Zset.List.hash Bitmap . 四种统计类型: 二值状态统计: 聚合统计: 排序统计: 基数统计 二值状态统计: 就是集合中的元素 ...
- C++ std-11 常用方法
对多个值取最值 C++标准库提供了获取最大值和最小值的方法: int mi = std::min(x1, x2); int ma = std::max(x1, x2); 如果想获取超过两个数的最值呢? ...
- 编写Java程序,将一个int型数组拼接成字符串
返回本章节 返回作业目录 需求说明: 将一个int数组中的元素拼接成int元素以逗号分隔字符串. 实现思路: 定义一个数组变量int[] arrs = {12,21,33,9,2}. 定义一个方法ar ...
- MySQL存储过程入门基础
创建存储过程无参语法: delimiter // create procedure 函数名() begin 业务逻辑 end // call 函数名() 通过函数名调用存储过程 创建存储过程有参与法: ...
- Typescript 字符串字面量类型
字符串字面类型定义的类型是固定的,在其使用时必须是其定义的其中一个字符串,否则会报错 当传入一个定义之外的字符串时,会报错字符串字面量类型.ts(13,20): error TS2345: Argum ...