看下面的面试题:

#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是未初始化的,因此其值也是不确定的。

提示: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的定义

inline void *__cdecl operator new(size_t, void *_P)
{
return (_P);
}

  从代码看来,没有分配内存。

struct CLS
{
int m_i;
CLS( int i ) : m_i(i){}
CLS()
{
new (this)CLS(0);
}
};

这里可以看到,new也可以操作栈上已经分配好的内存。另: 若构造函数调用自身,则会出现无限递归调用,是不允许的。

所以,在实际使用的时候,单纯的在构造函数中调用其它的构造函数,只是会产生一个临时的匿名变量。如果仅仅是为了重用代码,可以把重用的代码封装成一个新的函数。

[C++基础]在构造函数内部调用构造函数的更多相关文章

  1. c++构造函数中调用构造函数---匿名对象再探

    #include<iostream> #include<string> using namespace std; class Copy_construction { publi ...

  2. Java构造函数中调用构造函数

    在Java中,当为一个类创建了多个构造函数时,有时想在一个构造函数中调用另一个构造函数以减少代码量.这时可以使用this关键字来实现. 通常,当使用this关键字时,它意味着"这个对象&qu ...

  3. JS基础语法---创建对象---三种方式创建对象:调用系统的构造函数;自定义构造函数;字面量的方式

    创建对象三种方式: 调用系统的构造函数创建对象 自定义构造函数创建对象(结合第一种和需求通过工厂模式创建对象) 字面量的方式创建对象 第一种:调用系统的构造函数创建对象 //小苏举例子: //实例化对 ...

  4. [C#解惑] #1 在构造函数内调用虚方法

    谜题 在C#中,用virtual关键字修饰的方法(属性.事件)称为虚方法(属性.事件),表示该方法可以由派生类重写(override).虚方法是.NET中的重要概念,可以说在某种程度上,虚方法使得多态 ...

  5. java 构造函数内部的多态方法 完全剖析

    我们先来看一个例子,如果你读过<java编程思想>的话 应该会有印象 package com.test.zj; public class PolyConstructors { public ...

  6. [Java]构造函数内部多态的行为所引起的灾难

    构造函数内部的多态行为所产生的意想不到的结果 一.Java版本 1 package com.company; 2 import static com.brianyi.util.Print.*; 3 4 ...

  7. C++基础 (3) 第三天 构造函数 构造函数初始化列表 拷贝构造函数 析构函数 静态成员变量

    // 同类之间无私处 2构造函数 3析构函数 4构造函数的种类和析构函数的顺序 结论:析构函数的调用顺序,跟对象的构造顺序相反,谁先构造,谁最后一个被析构. 拷贝构造函数: 注意: 等号写在下面和写在 ...

  8. java静态方法调用&&构造函数&&静态块

    静态方法,也就是使用static声明的方法,在虚拟机启动加载类的时候就进行了创建,所以使用到静态方法时,直接使用类名点静态方法即可调用.java在执行静态方法前,不会调用构造函数:构造函数是在实例化j ...

  9. 关于在C#中构造函数中调用虚函数的问题

    在C#中如果存在类的继承关系,应避免在构造函数中调用虚函数.这是由于C#的运行机制造成的,原因如下: 新建一个类实例时,C#会先初始化该类(对类变量赋值,并将函数记在函数表中),然后再初始化父类.构造 ...

随机推荐

  1. check cable connection PXE-M0F: Exiting intel PXE ROM no bootable device-- insert boot disk and pre

    今天修电脑遇到一个问题,新买的电脑的原装的是linux,然后我按常规方式进入PE后重装系统,然后开机一直显示下面的代码,进不去: check cable connection PXE-M0F: Exi ...

  2. TNS-12541,TNS-12560,TNS-00511,TNS-12542,TNS-12560,TNS-00512数据库启动监听报错

    第 1章   数据库server监听错误 1.1.1数据库监听错误 1.1.1.1 问题及现象 server环境为ORACLE11G RAC环境,系统启动后,监听没起来. [oracle@RAC4 ~ ...

  3. HTML5图片预览

    两种方式实现 URL FileReader <!DOCTYPE HTML><html>    <head>    <meta charset="ut ...

  4. linux-FTP服务常用命令及测试

    一.vsftpd服务的安装,启动及关闭1.安装vsftpd[root@rusky bdump]# yum install vsftpd --必须配置yum源才能使用yum命令来安装vsftpd,或者挂 ...

  5. 基于zepto的手机焦点图touchstart touchmove

    基于zepto的手机焦点图,查看地址:demo (建议使用手机浏览器查看)代码如下: <!DOCTYPE HTML> <html> <head> <title ...

  6. (三)Android中Intent概念及应用

    一.显示Intent startActivity(new Intent(MainActivity.this,BAty.class)); 显示Intent直接指定要启动的Intent类 注意自己通过创建 ...

  7. zookeeper_00:zookeeper注意事项

    需要将应用数据和协同数据独立开. 比如:网络邮箱服务的用户对自己邮箱中的内容感兴趣,但是并不关心由哪台服务器来处理特定邮箱的请求.在这个例子中,邮箱内容就是应用数据,而从邮箱到某一台邮箱服务器之间的映 ...

  8. 判断是否联网_检测网络的类型为3G、2G、wap、wifi

    判断是否联网_检测网络的类型为3G.2G.wap.wifi  判断是否联网: /*** * judge Internet is available * * @author wei-spring * @ ...

  9. Linux定时任务Crontab命令详解

    linux 系统则是由 cron (crond) 这个系统服务来控制的.Linux 系统上面原本就有非常多的计划性工作,因此这个系统服务是默认启动的.另 外, 由于使用者自己也可以设置计划任务,所以, ...

  10. [solaris]odbc-oracle,简单测试

    #include <string> #include <iostream> #include <stdio.h> #include <sql.h> #i ...