带有虚函数的情况。

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

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++对象模型)的更多相关文章

  1. C++构造函数语义学(一)(基于C++对象模型)

    如果一个类没有自己的构造函数,编译器会在需要的时候为其合成一个出来,俗称:合成默认构造函数.但是请注意是在需要的时候,并不是所有情况. 请看下面代码: 1 #include<iostream&g ...

  2. C++构造函数语义学(三)(基于C++对象模型)

    带有虚基类的情况. 1 #include<iostream> 2 using namespace std; 3 class X 4 { 5 public: 6 int i; 7 }; 8 ...

  3. 构造函数语义学之Copy Constructor构建操作(2)

    二.详述条件 3 和 4 那么好,我又要问大家了,条件1 和 2比较容易理解.因为member object或 base class 含有copy constructor.那么member objec ...

  4. VSTO学习笔记(二)Excel对象模型

    原文:VSTO学习笔记(二)Excel对象模型 上一次主要学习了VSTO的发展历史及其历代版本的新特性,概述了VSTO对开发人员的帮助和效率提升.从这次开始,将从VSTO 4.0开始,逐一探讨VSTO ...

  5. 构造函数语义学——Copy Constructor 篇

    构造函数语义学--Copy Constructor 篇 本文主要介绍<深度探索 C++对象模型>之<构造函数语义学>中的 Copy Constructor 构造函数的调用时机 ...

  6. CRL快速开发框架系列教程二(基于Lambda表达式查询)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  7. Android消息推送(二)--基于MQTT协议实现的推送功能

    国内的Android设备,不能稳定的使用Google GCM(Google Cloud Messageing)消息推送服务. 1. 国内的Android设备,基本上从操作系统底层开始就去掉了Googl ...

  8. word2vec原理(二) 基于Hierarchical Softmax的模型

    word2vec原理(一) CBOW与Skip-Gram模型基础 word2vec原理(二) 基于Hierarchical Softmax的模型 word2vec原理(三) 基于Negative Sa ...

  9. 构造函数语义学——Default Constructor篇

    构造函数语义学--Default Constructor 篇 这一章原书主要分析了:编译器关于对象构造过程的干涉,即在对象构造这个过程中,编译器到底在背后做了什么 这一章的重点在于 default c ...

随机推荐

  1. SPringBoot 配置类继承WebMvcConfigurationSupport和实现WebMvcConfigurer的使用

    个人习惯使用  实现的方式 public class WebMvcConfiguration implements WebMvcConfigurer {

  2. Spring整合ActiveMQ,实现队列主题消息生产消费

    1.引入依赖 pom.xml 1 <!-- activemq --> 2 <dependency> 3 <groupId>org.springframework&l ...

  3. Linux(centos)系统导出数据库文件命令

    mysqldump -uroot -p test > /test.sql -uroot 其中的root是数据库的用户名 test是要导出的数据库名字 test.sql 是要导出的数据库文件名字, ...

  4. c/c++11封装UDP,支持ipv4和ipv6,支持接收和发送

    更新日志 11/06/2021 1.增加IPV6 2.ipv6通过windows10初步测试 3.ipv6包括: 接收和发送 5.增加错误代码接口 6.本机IPv6截图 7.编译通过截图 8.ipv6 ...

  5. 【LeetCode】1018. Binary Prefix Divisible By 5 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  6. 【LeetCode】862. Shortest Subarray with Sum at Least K 解题报告(C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 队列 日期 题目地址:https://leetcod ...

  7. 【LeetCode】142. Linked List Cycle II 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 双指针 set 日期 题目地址:https://le ...

  8. 【LeetCode】686. Repeated String Match 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  9. codevs 1300:文件排版(DP)

    题目描述 写电子邮件是有趣的,但不幸的是经常写不好看,主要是因为所有的行不一样长,你的上司想要发排版精美的电子邮件,你的任务是为他编写一个电子邮件排版程序. 完成这个任务最简单的办法是在太短的行中的单 ...

  10. Bristol大学密码学博士生的五十二个知识点

    Bristol大学密码学博士生的五十二个知识点 这个系列,是Bristol大学的密码安全工作组为密码学和信息安全相关的博士准备了52个基本知识点. 原地址:http://bristolcrypto.b ...