[C++基础]在构造函数内部调用构造函数
看下面的面试题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #include <iostream> using namespace std; struct CLS { int m_i; CLS( int i ) : m_i(i){} CLS() { CLS(0); } }; int main() { CLS obj; cout << obj.m_i << endl; return 0; } |
打印的结果是系统的一个随机值。所以这种直接在构造函数中调用另外的一个构造函数是不可行的。
代码奇怪的地方在于构造函数中调用了自己的另一个构造函数
我们知道,当定义一个对象时,会按顺序做2件事情:
1)分配好内存(非静态数据成员是未初始化的)
2)调用构造函数(构造函数的本意就是初始化非静态数据成员)
显然上面代码中,CLS obj;这里已经为obj分配了内存,然后调用默认构造函数,但是默认构造函数还未执行完,却调用了另一个构造函数,这样相当于产生了一个匿名的临时CLS对象,它调用CLS(int)构造函数,将这个匿名临时对象自己的数据成员m_i初始化为0;但是obj的数据成员并没有得到初始化。于是obj的m_i是未初始化的,因此其值也是不确定的。
1 2 3 4 5 6 | 提示:C++实例化对象的方式很多,特别是在栈中实例化对象,看下面的例子: CLS obj; 在栈中实例化一个对象,调用默认构造函数 CLS obj(10); 在栈中实例化一个对象,调用 int 参数的构造函数 CLS obj(); 这不是实例化对象,这是声明一个返回类型为CLS,参数为 void 的函数。当然这个函数声明可以在其他的函数内部 CLS(10); 调用 int 参数的构造函数在栈中产生一个匿名的对象,类似 new CLS(10);也是产生匿名的对象,只不过 new 时要有一个指针接收这个匿名对象 CLS(); 同上,只不过这里调用无参构造函数 |
从这里,我们归纳如下:
1)在c++里,由于构造函数允许有默认参数,使得这种构造函数调用构造函数来重用代码的需求大为减少
2)如果仅仅为了一个构造函数重用另一个构造函数的代码,那么完全可以把构造函数中的公共部分抽取出来定义一个成员函数(推荐为private),然后在每个需要这个代码的构造函数中调用该函数即可
3)偶尔我们还是希望在类的构造函数里调用另一个构造函数,可以按下面方式做:
当调用了一个类的构造函数,那么这个类的内存一定开辟好了,然后才调用构造函数初始化非静态成员变量的。
在构造函数里调用另一个构造函数的关键是让第二个构造函数在第一次分配好的内存上执行,而不是分配新的内存,这个可以用标准库的placement new做到:
先看看标准库中placement new的定义
1 2 3 4 | inline void *__cdecl operator new ( size_t , void *_P) { return (_P); } |
从代码看来,没有分配内存。
1 2 3 4 5 6 7 8 9 | struct CLS { int m_i; CLS( int i ) : m_i(i){} CLS() { new ( this )CLS(0); } }; |
这里可以看到,new也可以操作栈上已经分配好的内存。另: 若构造函数调用自身,则会出现无限递归调用,是不允许的。
所以,在实际使用的时候,单纯的在构造函数中调用其它的构造函数,只是会产生一个临时的匿名变量。如果仅仅是为了重用代码,可以把重用的代码封装成一个新的函数。
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· ThreeJs-16智慧城市项目(重磅以及未来发展ai)
· .NET 原生驾驭 AI 新基建实战系列(一):向量数据库的应用与畅想
· Ai满嘴顺口溜,想考研?浪费我几个小时
· Browser-use 详细介绍&使用文档
· 软件产品开发中常见的10个问题及处理方法