C++ - 对象模型之 编译器何时才会自行添加构造函数

2018 好未来面试 C++ 知识点随笔 不定时更新。遇到好的问题记录 [toc]好未来一面 智能指针实现机制,弱指针和智能指针 c++11的特性有哪些 lamda和函数对象的区别 继承的理解 virtual继承和普通继承 virtual函数和普通函数的区别 覆盖和重载 QQ窗口设计 函数对象,函数,函数指针,之间的关系 两个栈实现一个队列 如何查找一个链表的中位数 阅读详情

C++对象模型目录

C++ - 对象模型之 编译器何时才会自行添加构造函数

C++ - 对象模型之 内存布局

C++ - 对象模型之 成员函数调用

C++ - 对象模型之 构造和析构函数都干了什么

C++ - 对象模型之 类对象在执行时是如何生成的

C++ - 对象模型之 模板、异常、RTTI的实现


C++ - 对象模型之 编译器何时才会自行添加构造函数


Default Constructor的构建

如果没有声明构造函数,默认构造函数并不会都会构建,它必须符合四种情况才会构建。

情况一:包含的成员有一个带有Default Constructor的类对象
但是还有一个前提,该类对象成员必须有default constructor,因为生成Default Constructor的原因就是为了调用成员类的构造函数来初始化该成员。
如:
class C1{
public:
C1(){}
};


class C2{
private:
C1 c1;
};
由于C1有构造函数,那么C2就需要调用C1的构造函数来构造c1,所以C2会生成如下的构造函数:
inline: C2::C2(){
//伪码
c1.C1::C1();
}
另外,如果C2中已经有了构造函数,那么编译器会在构造函数里面也生成如上的伪码。

情况二:继承于一个带有Default Constructor的基类
还记得C++相关书籍说过,继承类构造的过程是基类先构造,然后是继承类再构造。那么如何才能使基类先构造呢?
1. 基类有Default Constructor;
2. 在继承类的构造函数首先调用基类的Default Constructor,然后再执行其他的初始化操作;

情况三:带有虚函数的类
带有虚函数类的对象有一个vptr指针指向虚函数表vtbl,那么就需要初始化这个vptr指针指向vtbl。这样编译器才能把每个对象的调用的虚函数通过虚函数表的方式调用到真正的函数。

情况四:虚拟继承的类
Class A{};
Class B : public virtual A{};
Class C : public virtual A{};
Class D : public B, public C{};

由于B* pb可以代表B对象也可以代表D对象,这些东西必须在执行期才能确定,由于对象B和对象D中A的偏移量(A一般都是在最后面)不一定,所以,就需要一个指针指向这个virtual base class。那么这个指针就需要在构造函数中初始化。

拷贝构造函数的构建

Bitwise Copy Semantics(位逐次拷贝)
什么是位逐次拷贝,C语言中Struct赋值,其实就将对应位置的元素进行赋值,这些对象在内存上是连续的,只需要将内存复制过去即可,在这样的简单情况下,是不需要拷贝构造函数的。也就是,当不符合位逐次拷贝时,拷贝构造函数才需要,才会被编译器创建出来。以下是,不符合位逐次拷贝的情况:
1. 类A有一个成员是类B的对象b1,并且类B有构造函数
试想,如果这个时候,类A没有构造函数,那么如何才能调用B的构造函数呢;既然没有构造函数,那么就是使用的位逐次拷贝,也就是对类B也是使用的位逐次拷贝,这显然是不对的,因为类B的构函数可能只是对部分成员进行的拷贝赋值。
2. 类A继承于类B,而类B有拷贝构造函数
情况和第一种情况差不多,拷贝时,必须调用B的构造函数,那么类A也就需要一个构造函数。
3. 类中含有虚函数
假设类Animal(动物类)和类Bear(熊类),熊继承于动物类,那么在Animal和Bear的对象里面都有vptr来指向应该调用的虚函数。如果Animal的对象A1复制给Animal的对象A2,或者Bear的对象B1复制给Bear的对象B2,是没有问题的,因为他们的调用的虚函数表是一样的,所以可以使用位逐次拷贝,直接将vptr拷贝过去即可。但是如果按照位逐次拷贝将A1复制给B1,就会出现问题,因为这样一来,B1的行为就变成了A1了,那么B1本来是一个熊,它喜欢偷蜂蜜,复制之后就不是一个熊了,它不再喜欢偷蜂蜜了,这显然是不妥的。同理,将B1复制给A1也不妥。所以,这样的情况下,就需要有一个构造函数,来设定vptr的指向。
4. 虚拟继承的类
如:
Class Bear : public virtual Animal
Class Pander : public Bear

Pander p;
Bear b = p;
如果以位逐次拷贝会出现什么情况,p和b的内存布局可能如下:
p:
Bear Data
Pander Data
Animal Data
b:
Bear Data
Animal Data

b=p会使,b丢失Animal虚拟基类的信息,而多了Pander Data(普通熊是不需要熊猫的属性的)
这显然是不妥的,所以需要一个构造函数,使b只获得p的部分属性(普通熊的属性)和Animal的属性。
总之,只要上面四种情况至少之一符合,则需要编译器创建一个构造函数。

成员初始化列表

以下几种情况,是必须使用初始化列表的:
1. 当member是引用或者const时
我们知道引用和const变量初始化时必须进行赋值,那么编译在初始化这些成员时,就会将成员初始化。如果不在初始化列表,而是在构造函数里赋值,那么就将分配变量和变量赋值分离,显然无法通过编译。
2. 基类没有Default Constructor而有带参数的Constructor
继承类构造时,会先构造基类,由于基类的构造函数有参数,而如果我们不显示指定这个参数,那么显然也是编译不同过的。但是如果构造函数参数都有默认值,就不会出错。
3. 成员类没有Default Constructor而有带参数的Constructor
和第二种情况相似,构造函数必须构造member Class,由于Member Class的构造函数有参数,而我们不指定这个参数,那么显然也是无法编译通过的。同样,如果构造函数参数都有默认值,就不会出错。

效率分析
对于普通类型成员,在初始化列表初始化和在构造函数初始化效率一样,但是如果初始化的是类对象,那么在初始化列表初始化,其实编译器会在构造函数直接通过构造函数构造类对象,而如果是在构造函数通过赋值构造类对象,那么编译器会先构造初始值,然后通过拷贝构造函数构造成员类对象,最后将初始值析构。明显效率会降低。

注意
初始化列表初始化的顺序是按照声明的次序而不是初始化列表的顺序初始化。这也可以理解,因为按照惯性思维,我们对内存的分配和初始化是顺序的,而内存上面的次序和声明次序是一致的。





C++编译器为类自动生成的函数 我们可以构建一个空类,class Empty { }; 尽管没有定义任何函数,但我们可以通过以下方式使用这个类:Empty e1; Empty e2(e1); e2 = e1; 因为当编译器发现你用上述方式使用这个类而却在类声明中没有定义一般构造函数(非复制构造函数)、复制构造函数、赋值操作符重载函数和析构函数时,会自动为其生成这些函数,上面的Empty类经编译后就对应着下面的类:class Emp 阅读详情

相关推荐

C++编译器会对没有构造函数的类生成默认构造函数吗?

之前在上C++的课的时候,印象中有那么一句话: 如果一个类没有任何构造函数,那么编译器会生成一个默认的构造函数 今天在看《深度探索C++对象模型》的第二章:“构造函数语意学”的时候发现之前听到的说法是错误的。 比如说如下代码: class A { public: int a; }; int main(void) { A a; a.a = 4; A a2; ...

个人博客 4862

何时编译器会自动生成默认构造函数

问题:对c++初学者来说存在一个误区,如果类没有定义任何构造函数,编译器会自动生成默认的构造函数。 注意:这种说法是错误的。 正确的说法:惟有默认构造函数”被需要“的时候编译器才会合成默认构造函数。 那什么情况下是“被需要”的时候? 以下有四种情况编译器会自动合成默认构造函数 情况1含有类对象数据成员,该类对象类型有默认构造函数 即:一个class含有类对象数据成员,该类对象类型...

weixin_41066529的博客 2373

C++中复制构造函数何时调用?什么时候需要自定义副本构造函数

什么是复制构造函数? 复制构造函数是一个成员函数,它使用同一个类的另一个对象初始化一个对象。函数原型如下: ClassName(const ClassName &old_obj); 下面是一个复制构造函数的简单示例: #include <iostream> using std::cout; class Point { private: int x, y; publi...

a15322910600的博客 2028

c++编译器加的函数

C++默认编写并调用哪些函数一个empty class经过c++处理之后,编译器会为其声明(编译器版本的)一个copy构造函数、一个copy assignment操作符和一个析构函数。此外,如果没有声明任何构造函数,编译器会声明一个default构造函数。所有这些函数是public 和inline。class Empty{}等价于class Empty{ public : E

LC900730的博客 474

C++对象模型之复制构造函数的构造操作

复制构造函数用于根据一个已有的对象来构造一个新的对象。1、构造函数何时被调用有三种情况会以一个对象的内容作为另一个类的对象的初值构造一个对象,分别是:1)对一个对象做显示的初始化操作时,如class X { ... };X x;X xx = x; // 或 X xx(x);2)当对象被当作参数传递给某个函数时3)当函数返回一个类的对象时2、默认的成员复制初始化如果class没有提供一个显式的复制构

ljianhui的专栏 2448

C++对象模型之默认构造函数的构造操作

一个类,如果没有任何的用户声明的的构造函数,那么会有一个默认的构造函数被隐式地声明出来。这个被隐式声明的构造函数,究竟什么时候被合成、被编译器合成的默认构造函数究竟执行怎么样的操作,编译器如何处理用户定义的构造函数,就是本文要探讨的问题。 1、默认构造函数何时被合成 如果一个类没有任何的用户声明的构造函数,那么在当编译器需要的时候,编译器会为类合成一个默认的构造函数,它只用于执行编译器所需要

ljianhui的专栏 3189

为类模板加上构造函数和默认构造函数

#include #include using namespace std; template class Test { public:     Test();     Test(T1 d1, T2 d2);     template Test(const Test &t);     void SetData1(T1 val)     {         data1

l724430310的博客 1万+

基于STM32与CAN总线的多电机协同控制系统设计与实现

本文详细介绍了基于STM32与CAN总线的多电机协同控制系统设计与实现。该系统采用分布式架构,通过CAN总线实现多节点通信,结合梯形加减速算法和同步控制策略,有效解决了工业自动化中多电机同步性差的问题。文章涵盖硬件设计、通信协议、抗干扰措施及实战调试经验,为工业应用提供高可靠性解决方案。

tech5的博客 970

C++【对象模型】|【02】构造函数何时才会被编译器自动生成?

文章目录一、默认构造函数1、何时默认构造函数会自动生成2、编译器合成有用的构造函数四种情况2.1 类中内含带有默认构造的类成员 一、默认构造函数 1、何时默认构造函数会自动生成 当类没有提供默认构造时,如果编译器需要它,则将会为其添加上;如果是程序的需要,则需要我们手动为它添加; 如何区分编译器需要还是程序需要 当使用`foo f;`创建一个对象时, - 由于类中没有提供默认构造函数,编译器会自动为其生成使之能被创建成功; - 类中的数据成员初始化交给构造函数,当想要默认的构造函数能够初始化数据成员(a)

weixin_45926547的博客 934

知识图谱-Neo4j-开始构建知识图谱-01

关系(Relationships):连接两个节点,具有方向(→ 或 ←)和类型(Type),可附加属性。 属性(Properties):键值对,存储节点或关系的详细信息(如 , )。 (2) Cypher 查询语言 直观语法:通过模式匹配直接描述图结构。 高效遍历:支持复杂关系路径查询(如最短路径、模式匹配)。 3. 核心优势 (1) 原生图存储 物理存储优化:数据以图结构直接存储,避免传统数据库的“表连接”开销。 高效遍历:通过指针直接访问相邻节点,时间复杂度接近 O(1)。 (2) 高性

寓教于乐。教己助人 1万+

2. Netty使用JSerialComm进行串口读取(二)

现在开始处理这些问题 第一个问题:串口读取超时异常一路传播到最后也没有处理。 ​ 第二个问题:即使处理了该异常,程序仍然退出,这不能满足一些实际使用要求需求。该问题与设置很长的读取超时时间没关系,无论多长到时间后总会退出。

s3c2410的博客 2461

C++何时调用构造函数,何时调用析构函数

前言

日常学习记录 1万+

Codex全网避坑实录|境外手机号封禁\+Ollama千问适配失败\+第三方中转站TOML全套配置

原生Codex:国内手机号百分百无法登录,PIN验证、多因子验证全部无效,不用尝试API Key登录:仅解锁界面,不充值无法使用功能,纯过渡方案Ollama本地千问:原生接口和Codex不兼容,手写Python代理大概率调试失败,不推荐折腾网页解析失败:只改wire_api为responses即可解决,无需修改接口地址使用建议:仅体验功能用中转站;长期办公提效,成本很高,建议改用兼容接口的本地模型。

驽马不舍 1896

C++对象模型-默认构造函数

title: C++对象模型–默认构造函数 author: Qian Jipeng tags: 默认构造函数 初始化列表 虚函数 虚基类 vtbl vptr 对象模型 categories: C++ date: 2019-08-30 13:45:00 这篇文章主要讲解C++中默认构造函数的机制,同时解决了困扰了我很久的问题,长篇文章,话不多说,开干! 写在前面 C++编译器为程序员自动提供下...

MokeeQian的博客 2166

AHB总线协议

1. 简介         AHB总线规范是AMBA总线规范的一部分,AMBA总线规范是ARM公司提出的总线规范,被大多数SoC设计采用,它规定了AHB (Advanced High-performance Bus)、ASB (Advanced System Bus)、APB (Advanced Peripheral Bus)。AHB用于高性能、高时钟频率的系统结构,典型的应用如ARM核与系统内

ivy_reny的专栏 8万+

3GPP LTE/NR信道模型

CDL(Clustered Delay Line):簇延迟线模型,包括CDL-A、CDL-B、CDL-C三个用于NLOS的信道模型,以及CDL-D、CDL-E两个用于LOS的信道模型。

LinkEverything的博客 1万+

什么是默认构造函数?

对于C++默认构造函数,我曾经有两点误解: 类如果没有定义任何的构造函数,那么编译器(一定会!)将为类定义一个合成的默认构造函数。 合成默认构造函数会初始化类中所有的数据成员。 第一个误解来自于我学习C++的第一本书 《C++ Primer》,在书中392页:“只有当一个类没有定义构造函数时,编译器才会自动生成一个默认构造函数”。实际上这句话也没有说错,它说明了默认构造函数定义的必要非充分条件,然而

熊俊坤的博客 1万+

张力控制速度闭环控制算法

这个算法的核心思想是通过比较实际速度和期望速度的差异来调整控制信号,以达到稳定的速度控制。比例项用于直接根据误差调整输出,积分项用于积累误差并进行补偿,微分项用于预测误差的变化趋势并进行调整。张力控制是在许多工程和工业应用中非常重要的一个过程,它涉及到通过调节力的大小来实现稳定的工作状态。通过合理设置比例、积分和微分系数,并结合实际系统的特性进行调试和优化,可以实现准确稳定的张力控制。速度闭环控制算法通过比较实际速度和期望速度之间的差异,并根据差异调整系统的输出,以保持速度稳定。

LiJavascript的博客 1302

深度探索C++对象模型之美

从概念来上来讲,每一个没有定义构造函数的类都会由编译器来合成一个默认构造函数,以使得可以定义一个该类的对象,但是默认构造函数是否真的会被合成,将视是否有需要而定。C++ standard 将合成的默认构造函数分为 trivial(不重要) 和 notrivial(重要) 两种,前文所述的四种情况对应于notrivial默认构造函数,其它情况都属于trivial。对于一个trivial默认构造函数,编译器的态度是,既然它全无用处,干脆就不合成它。

谢谢大家的关注 3494

无需Python环境!纯C#上位机+OpenCVSharp4+ONNX Runtime实现YOLOv8摄像头实时流检测,工业级稳定

摘要 工业自动化C#开发中,传统Python方案实现视觉检测功能存在环境依赖、内存泄漏和性能不稳定等问题。本文提出基于.NET 8+OpenCVSharp4+ONNX Runtime的纯C#方案,通过实际案例验证其优势: 零Python依赖,支持离线部署 内存稳定(380MB/72h),检测延迟<80ms 检测精度达漏检率<0.1%,误检率<0.5% 保留原有业务逻辑代码,3天完成适配 方案采用分层架构设计,支持多种硬件平台和操作系统,提供从模型导出到部署的全流程指导,为工业视觉检测提供高

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 196

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

《深度探索C++对象模型》(一)对象模型、存储形式;默认构造函数一定会构造么?

一)、读后感     在我参加工作两年多的时候,工作不算很忙了,《深入理解C++对象模型》开始进入我的视野;或许是因为我要从Symbian.C++ 转向iOS Objective-C,并开始思考语言本身的一些东西的缘故。     其实在一年前,出于对C++的迷惑,我已经买了这本书。当时翻了几页竟然没懂,就搁那儿了!可是现在,它让我随身携带、流连忘返、是个旅途好伴侣;看到它我精神抖擞,它给了我继

郭晓东的专栏 6336

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

《深入探索C++对象模型》之一

前言:        由于经常使用C++,但是又对C++内部机制不是很深入了解,所以看了一些关于C++的经典书籍,其中有《C++ Primer》、《STL源码剖析》、《Efficitive C++》、《More Efficitive C++》。《C++ Primer》特别适合刚使用C++的程序员学习,里面详细介绍了一些C++基础知识,包括流和STL容器、适配器、算法还有C++的面向对象的一些知识。...

杨林峰的笔记 8912

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

《深度探索C++对象模型》阅读笔记(完整版)

《深度探索C++对象模型》完整阅读笔记

2401_82413779的博客 1903

深度解读《深度探索C++对象模型》之C++默认构造函数

C++的默认构造函数的作用是什么?什么时候会需要一个默认构造函数,以及默认构造函数从哪里来?这篇文章将从编译器的角度来分析这个问题。

iShare_Carlos的博客 1377

67 C++对象模型探索。C++编译器在什么给我们生成默认的拷贝构造函数?

传统上,大家认为:如果我们没有定义一个自己的拷贝函数,编译器会帮助我们合成一个 拷贝 构造函数。实际这个也是不对的,这个合成的拷贝构造函数,也是在必要的时候才会合成出来。我们这节就研究一下这个必要的时候是什么时候。验证方法:将.obj文件使用工具 dumpbin 命令导出,查看 copy 构造函数的关键字:那么这个关键字应该是什么呢?

hunandede的博客 923

Cpp 对象模型探索 / 编译器为对象创建缺省构造函数的条件

零、前言 书本上常说,编译器会给没有任何构造函数的类自动创建一个缺省的构造函数(没有形参的构造函数)。但是事实上不是这样么?栗子: class A { public: int i; }; int main() { A a; return 0; } 编译上述代码,生成 test1.obj 文件。 这里为了检查编译器是否为我们创建了 a的构...

布袋和尚 401
上一篇: C++ - 对象模型之 成员函数调用
下一篇: Android - Binder应用分析
G机器猫
博客等级 码龄16年 106粉丝 74原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值