题目如下:问下列代码的打印结果为0吗?
#include <stdlib.h>
#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;
system("PAUSE");
return 0;
}
打印结果是不定的,不一定为0
代码奇怪的地方在于构造函数中调用了自己的另一个构造函数
我们知道,当定义一个对象时,会按顺序做2件事情:
1)分配好内存(非静态数据成员是未初始化的)
2)调用构造函数(构造函数的本意就是初始化非静态数据成员)
显然上面代码中,CLS obj;这里已经为obj分配了内存,然后调用默认构造函数,但是默认构造函数还未执行完,却调用了另一个构造函数,这样相当于产生了一个匿名的临时CLS对象,它调用CLS(int)构造函数,将这个匿名临时对象自己的数据成员m_i初始化为0;但是obj的数据成员并没有得到初始化。于是obj的m_i是未初始化的,因此其值也是不确定的
从这里,我们归纳如下:
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);
}
};
参考:http://www.cnblogs.com/chio/archive/2007/10/20/931043.html
另: 若构造函数调用自身,则会出现无限递归调用,是不允许的
对于派生类调用基类构造函数初始化的时候,必须在派生类的构造函数的初始化列表里面进行调用基类构造函数,(因为C++中, 初始化列表中先执行完成, 先于构造函数体内执行. 即成员真正的初始化发生在初始化列表中, 而不是构造函数体中)继承类中调用基类初始化构造函数, 实际上就是先构造基类对象, 必须使用初始化列表即;B(int i,int j,int k) : A(i) // 显示调用基类有参构造函数
(当然,如果没有定义带参的构造函数也可以不在初始化列表显示调用而让编译器调用默认构造函数: B(int i) // 隐式调用基类缺省构造函数).
否则,如果把基类构造函数放在构造函数体内部
B(int i,int j,int k)
{
A(i);
}
调用就会和上面构造函数调用构造函数中相似,会产生一个临时对象,实际上没有初始化要定义的类对象,这时候编译器调用的是默认构造函数。
-
class A {
-
int a;
-
public:
-
A() { a=0; } // 基类缺省构造函数
-
A(int i)
-
{ a=i; } // 基类有参构造函数
-
void print() { cout<<a<<”,”; } };
-
class B:public A
-
{
-
int b1,b2;
-
public:
-
B( ) // 隐式调用基类缺省构造函数
-
{ b1=0; b2=0; }
-
-
B(int i) // 隐式调用基类缺省构造函数
-
{ b1=i; b2=0; }
-
-
B(int i,int j,int k) : A(i) // 显示调用基类有参构造函数
-
{ b1=j; b2=k; }
-
void print()
-
{ A::print(); cout<<b1<<”,”<<b2<<endl; }
-
};
阅读(447) | 评论(0) | 转发(1) |