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 ...
随机推荐
- JAVA中CountDownLatch的简单示例
public static void main(String[] args) throws InterruptedException { CountDownLatch latch =new Count ...
- AndroidStudio-快捷键
Windows: Ctrl + Alt +L (Ctrl +Shift+F 无效) (亲测,和qq热键冲突,我的解决方式是把qq除捕获屏幕外的热键全部设置为无) Mac: OPTION + CMD + ...
- 【LeetCode】42. Trapping Rain Water 接雨水 (C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 暴力求解 保存左右最大值 单调栈 日期 题目地址:ht ...
- matplotlib 高阶之path tutorial
目录 Bezier example 用path来画柱状图 随便玩玩 import matplotlib.pyplot as plt from matplotlib.path import Path i ...
- IM2603设计资料 Type-C拓展坞电源管理芯片
应用于Type-C拓展坞外围集成Buck变换器的电源管理芯片 IM2603 IM2603 概述 用于带有集成降压转换器的 Type-C 外围应用的电源管理 IC IM2603 是一款主要用于 Type ...
- Oracle中的基本数据类型
一.Oracle 基本数据类型 1.字符数据类型 CHAR:存储固定长度的字符串,如果没有指定长度,默认为1个字节,如果数据长度没有达到指定的长度,则通过填充空格的方式来使其达到定义的长度(CHAR类 ...
- SpringBoot集成Actuator监控管理
1.说明 本文详细介绍Spring Boot集成Actuator监控管理的方法, 基于已经创建好的Spring Boot工程, 然后引入Actuator依赖, 介绍监控管理相关功能的使用. Sprin ...
- Hadoop问题解决记录
# 1.解决Unable to load native-hadoop library for your platform告警 安装Hadoop启动之后总有警告:Unable to load nativ ...
- Java--Map的使用认知
Java里面的Map是一个抽象接口,有一些类实现的该接口比如HashMap.TreeMap等 HashMap 是一个散列表,存储的内容是靠键值对来映射的(key-value). 基本认识 HashMa ...
- pip list 精确查找某一模块的方法
1. 今天搜资料的时候get一项技能: pip list精确查找某一模块 命令如下: pip list | findstr "win32" (此处win32可以替换成任意想查找的模 ...