看下面的面试题:

#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. ER 和 数据库关系模式

    http://lianghuanyue123.blog.163.com/blog/static/130423244201162011850600/ 我们眼下所接触的数据库基本上是关系数据库,关系数据库 ...

  2. PHP高级特性基础

    php对象在内存中的区域:php对象名和对象存放的位置是不一样的,这一点和java是一模一样的,所以在php面向对象部分你完全可以套用java的思想去做.对象存放在堆区(heap)而对象名则和其他普通 ...

  3. CSS3 过渡

    通过 CSS3,我们可以在不使用 Flash 动画或 JavaScript 的情况下,当元素从一种样式变换为另一种样式时为元素添加效果. 请把鼠标移动到右侧的元素上: 浏览器支持 Internet E ...

  4. 跳跃表 C#

               虽然avl树和红黑树在数据搜索和排序方面都是有效的数据结构,但是都显得特别麻烦,跳跃表就显得特别简单,虽然简单 不影响他性能,在平均情况下,其插入.删除.查找数据时间复杂度都是O ...

  5. jvm强制类型转换

    public class Integer_Object { public static void main(String[] args){ Object obj = new ooo(); // Int ...

  6. poj3254Corn Fields题解

    Corn Fields Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 9623   Accepted: 5092 Descr ...

  7. Python面向对象关系

    首先了解一下Python面向对象中类型-实例和父类-子类的关系.下面的一些规则很有用. 当我们介绍许多不同的对象时,我们只用了两种关系(图4.1 关系): 是一类(is a kind of)(实线): ...

  8. 通过js控制html页面不能右键,复制等

    <script type="text/javascript"> //Method one //<![CDATA[ //document.oncontextmenu ...

  9. JS基础如何理解对象

    这几天跟几个同事聊天发现他们对javascript什么时候该用new都不是很了解. 1.javascript的function什么时候该new什么时候不该new?我觉得主要的问题还是集中在javasc ...

  10. not valid for Running the scheme

    The run destination iPhone6 Plus is not valid for Running the scheme 'MyApp’. Phone6 Plus's iOS 8.0 ...