当前位置:网站首页>C-默认构造函数什么情况下才真正被合成
C-默认构造函数什么情况下才真正被合成
2022-08-08 06:20:00 【亓逸】
C++ 默认构造函数什么情况下才真正被合成
前提知识:C++ 默认构造函数为什么存在以及编译器怎么实现
对于class X,如果没有任何user-declared constructor,那么就会有一个default constructor被隐式(implicitly)声明出来······ 一个被隐式声明出来的default constructor将是一个trivial(浅薄而无能,没啥用的)constructor······ ——摘自《深度探索C++对象模型》
首先需要解读上面这句话,在类设计的过程,类成员中没有提供一个用户自定义的构造函数,编译器会隐式声明一个默认构造函数给类。但是这个默认构造函数中做了什么?是否对类的构造有作用?
这是笔者一开始学习该知识过程中所不具备的知识。
什么是nontrivial constructor?
如果一个class没有任何constructor,但它内涵一个member object,而后者有default constructor,那么这个class的implicit constructor就是"nontrivial(有用的)"
编译器需要为该class合成一个default constructor。不过这个合成操作只有在constructor 真正需要被调用时才会发生
“带有Default Constructor” 的 Member Class Object
举个例子,在下面的程序片段中,编译器为 class Bar 合成一个 default construction:
class Foo { public: Foo(), Foo(int) };
class Bar { public: Foo foo; char* str; };
void foo_bar()
{
Bar bar; // Bar::foo 必须在此处初始化
if ( str ) { } ...
}
被合成的Bar default constructor 内含必要的代码,能够调用class Foo 的 default constructor 来处理member object Bar::foo,但它并不产生任何代码来初始化Bar::str。因为在开发者角度上出发,Bar::foo初始化是编译器的责任,将Bar::str初始化则是程序员的责任。被合成的default constructor 看起来可能是这样的
inline
Bar::Bar()
{
foo.Foo::Foo();
}
但在程序员定义的default constructor中
Bar::Bar() { str = 0; }
现在程序员的需求的满足了,但是编译器还需要初始化member object foo,由于default constructor 已经被现实定义出来,编译器无法合成第二个。
那么这个时候编译器的行动是
如果class A内含一个或一个以上的member class objec,那么class A的每一个constructor 必须调用每一个member classes的default constructor
延续上诉的例子,扩张后的constructor可能是这样的
Bar::Bar()
{
foo.Foo::Foo();
str = 0;
}
多个member class object,则按照声明顺序,按序初始化
Bar::Bar()
{
foo.Foo::Foo();
foo1.Foo:Foo();
foo2.Foo::Foo();
str = 0;
}
“带有Default Constructor” 的 Base Class
与上述道理相似。
如果一个没有任何constructors的class派生自一个"带有default constructor" 的 base class,那么这个derived class 的default constructor 会被视为nontrivial,并因此需要被合成出来。它将调用上一层base classes的default constructor(根据它的声明顺序)。对一个后继派生的class而言,这个合成的constructor 和 一个"被显示提供的default constructor" 没有什么差异
“带有一个Virtual Function” 的 Class
另外有两种情况,也需要合成default constructor:
- class声明(或继承)一个virtual function
- class派生自一个继承串链,其中有一个或更多的virtual base classes
如"带有一个Virtual Function" 的 Class这一前提
有两个扩张的行为会在编译期间发生:
- 一个virtual function table会被编译器产生出来,内放class的virtual function地址
- 在每一个class object中,一个额外的pointer member(也就是vptr)会被编译器合成出来,内含相关之class vtbl的地址
故对于那些未声明任何constructions的classes,编译器会为它们合成一个default constructor,以便正确地初始化每一个class object的vptr
“带有一个Virtual Base Class” 的 Class
前提:菱形继承所涉及到的虚继承
class X { public : int i; };
class A : public virtual X { public : int j; }
class B : public virtual X { public : double d; }
class C : public A, public B { public : int k; }
//无法再编译期决定 pa->x::i 的位置
void foo( const A* pa ) { pa->i = 1024; }
操作需要在运行期才得以确认,为了符合这样的实现策略
//可能的编译器转变操作
void foo( const A* pa ) { pa->_vbcx->i = 1024; }
其中_vbcx表示编译器所产生的指针,指向virtual base class X
总结
在上述4种情况下的class 中没有声明constructor的时候,由于缺乏user声明的constructions,编译器都会生成一个nontrivial constructor,将详细记录合成一个default cons的必要信息。
所以C++ 新手一般有两个常见的误解:
- 任何class如果没有定义default constructor,就会被合成出一个来。
- 编译器合成出来的default constructor 会显式设定”class 内每一个data member的默认值
没有一个是真的!
边栏推荐
- from sklearn import cross_validation 报错的解决方法
- The tests that need to be done in the development of medical device products
- 李沐老师 PyTorch版——线性回归 + softmax回归的简洁实现(3)
- 【RPC】Mercury RPC
- 网络安全:系统文件属性
- string hash hash value
- leetcode 232. Implement Queue using Stacks 用栈实现队列(简单)
- State Compression Review
- 基于FTP协议的文件上传与下载
- “忙碌”的 Polkadot最新努力,对DOT投资者意味着什么?
猜你喜欢

PostgreSQL中想新建一个用户,让他仅能访问指定数据表,不能通过客户端工具看到表结构和函数内容,是否有方案可解决?

教你六步拆解 DDD领域驱动设计落地实践

APISIX Ingress v1.5-rc1 发布

torch.gather() 用法解读

kdeplot()核密度估计图的介绍

线上接口流量突增,快要扛不住了

The pta patching simple graph theory

YoloV4训练自己的数据集(四)

navicat15 连接Oracle数据库 报错ORA-28547: connection to server failed, probable Oracle Net admin error的解决方案

10道集合框架面试题(含解析),来看看你会多少
随机推荐
string hash hash value
scikit-learn随机数据生成实例
Key technologies for 4G/5G spectrum resource coordination
webstorage
YoloV4训练自己的数据集(二)
flex布局属性简约速记
uniapp H5 签名横版生成图片
torch.gather() usage interpretation
Why should Latches be avoided in digital IC design?
oracle insert sql error
使用C语言实现Hailstone序列
docker安装Mysql和其数据持久化
And an array merge rank by rank
tkinter-TinUI-xml combat (7) PDF paging and merging
刚学,这是怎么回事,SQL怎么转运错误啊
MySQL数据库
kdeplot()核密度估计图的介绍
Validated plan
2-SAT
【RPC】Mercury RPC