九月鹰飞

慎独自修,忠恕宽容,至诚尽性。

  VC知识库BLOG :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 登录 ::
  19 随笔 :: 13 文章 :: 158 评论 :: 3 Trackbacks
<2008年11月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456

留言簿(6)

随笔分类

随笔档案

文章分类

文章档案

相册

搜索

最新评论

阅读排行榜

评论排行榜

关于这个问题,曾经讨论过,apnic也总结过关于“在构造函数中调用构造函数”的问题。

#include <iostream>
using namespace std;

class A
{
public:
    A();
    A(int i);
    int data;

    ~A();
};

A::A()
{
    cout<< " call A::A() " << endl;
    data = 0;
}
A::A(int i)
{
    cout<< " call A::A(int) " << endl;
    data = i;
}
A::~A()
{
    cout<< " call A::~A() " << endl;
}

class B:public A
{
public:
    B();
    B(int i);
    ~B();
};

B::B(int i)
{
    cout<< " call B::B(int) " << endl;
    B();
}

B::B():A(10)
{
    cout<< " call B::B() " << endl;
}
B::~B()
{
    cout<< " call B::~B() " << endl;
}
void main()
{
    B b(2);
    cout<< b.data << endl;
}
一般认为B b(2);应该调用B::B(int i)构造函数,里面调用B();
而B::B()调用的是A(10)构造函数,A::A(int i)会把data设置成i,就是10。
但是运行结果是0:

call A::A()          //调用B(int)之前,先调用基类的缺省构造函数
call B::B(int)       //调用B(int)
call A::A(int)       //由于B()中使用了初始化列表,这里先调用了A(int)
call B::B()          //然后才调用了B()
call B::~B()         //居然调用析构函数
call A::~A()         //自然也会调用基类的析构函数
0                     //结果
call B::~B()         //再次析构,销毁对象
call A::~A()

从上面的调用过程中,可以看到只要调用类的构造函数,就会在栈中创建对象,是这样子的么?

但是如果改成构造函数中调用父类的构造函数:
B::B(int i)
{
 cout<< " call B::B(int) " << endl;
 A::A(i);  //call this constructor.
}
运行结果是:
call A::A()          
call B::B(int)      
call A::A(int)      
call A::~A()      
0                    
call B::~B()  
call A::~A()
少了对B的构造函数和析构函数的调用,但是仍然调用了~A(); 这是为什么?

看来只能改成这样:
B::B(int i):A(i)   
{
 cout<< " call B::B(int) " << endl;
}
运行结果是:
call A::A(int)
call B::B(int)
2  
call B::~B()
call A::~A()
只有这个结果是正确的,难道父类的构造函数只能在初始化列表中使用?

posted on 2005-06-12 09:41 九月鹰飞 阅读(5390) 评论(3)  编辑 收藏

评论

# re: 星星来看看 2005-06-12 13:04 周星星
“只要调用类的构造函数,就会在栈中创建对象,是这样子的么?”
--- 为什么你觉得 A(i) 是调用类的构造函数,而不是创建一个无名对象呢?从语法上讲它们都说得过去。
void foo( const string& msg )
{
   cout << string("MSG: ") + msg << endl;
} 中的 string("MSG: ") 是调用string的构造函数,还是创建一个无名对象?

“A::A(i);  //call this constructor.”
--- 同上。

Java/C#可以这样做,无可厚非,因为java/c#的class比C++ class少一个有用的功能,在C++中一个对象生存期结束时会自动调用析构函数(有人说Java能,有人说C#能,……,),而java/c#必须手工完成,之所以如此习性,则又需要归咎于垃圾收集。比如C#中的文件类,写入一个"abc",如果忘了调用Close函数,那么白写了。
“在C++中一个对象生存期结束时会自动调用析构函数”是有一个前提的,这个前提就是这个对象成功调用了构造函数(没有成功调用构造函数之前能称为对象吗?只能称为生鲜内存块^_^)。考虑如下代码:
constructor()
{
}
constructor( int )
{
做一些影响构造以及析构的操作
constructor()
throw exception //
}
那么constructor(0)这个对象还要不要调用析构函数?


# 感谢。 2005-06-13 09:26 iwaswzq
这句话:“为什么你觉得 A(i) 是调用类的构造函数,而不是创建一个无名对象呢?从语法上讲它们都说得过去。 ”真是一语惊醒梦中人。
第二个问题:
B::B(int i)
{
 cout<< " call B::B(int) " << endl;
 A::A(i);  //这里可以理解为创建了一个无名对象,然后又析构了?.
}
看来这么理解,再看输出就明白了。:)

# re: 星星来看看 2007-06-08 13:14 l0he1g
其实不仅仅在构造函数中如此,只要是在成员函数中都是这样的,原因是,不要忘了构造this指针也是构造函数的任务之一。

标题  
姓名  
主页
验证码 *
内容   
  登录  使用高级评论  Top
[使用Ctrl+Enter键可以直接提交]