返回信息流先是一段程序:
//声明类class
class Student
{
public:
Student(void); //默认构造函数
Student(int num, string name, char sex);
~Student(void);
void Display(void);
private:
int m_num;
//char m_name[SIZE];
string m_name;
char m_sex;
};
//类的实现
Student::Student(void)
{
m_num = 1001;
m_name = "Brian";
m_sex = 'M';
cout << "DefaultConstructor" << endl;
}
Student::Student(int num, string name, char sex) : m_num(num), m_name(name), m_sex(sex)
{
cout << "Constructor" << m_name << endl;
}
Student::~Student(void)
{
cout << "Destructor" << m_name << endl;
}
void Student::Display(void)
{
cout << "num: " << m_num << '\n';
cout << "name: " << m_name << '\n';
cout << "sex: " << m_sex << endl;
}
//main函数
int main(void)
{
Student stud[2] =
{
Student(1002, "lisa", 'F'),
};
stud[0].Display();
stud[1].Display();
return 0;
}
//程序结果
Constructorlisa
Destructorlisa
DefaultConstructor
num: 1002
name: lisa
sex: F
num: 1001
name: Brian
sex: M
DestructorBrian
Destructorlisa
C++ Primer Plus的解释是:
初始化对象数组的方案是,首先使用默认构造函数创建数组元素,然后花括号中的构造函数将创建临时对象,然后将临时对象的内容复制到相应的元素中。
为什么对于stud[1]会只调用一次构造函数,却调用两次析构函数?具体的数组创建过程是什么?
请达人指点迷津!多谢~~~
这是一条镜像帖。来源:北邮人论坛 / soft-design / #22328同步于 2007/11/17
该镜像源已超过 30 天没有更新,可能在源站已被删除。
SoftDesign机器人发帖
[求助]C++中有关对象数组的初始化与构造函数的问题
epeeist
2007/11/17镜像同步9 回复
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
【 在 epeeist 的大作中提到: 】
C++ Primer Plus的解释是:
初始化对象数组的方案是,首先使用默认构造函数创建数组元素,然后花括号中的构造函数将创建临时对象,然后将临时对象的内容复制到相应的元素中。
~~~~~~~~~~~~
这里复制应该是指 用拷贝构造函数复制到元素中的。所以还是有两次构造的
我后来又想了想,不知道是否可以这样解释:
构造函数的作用只是对对象的值进行初始化,而为对象分配空间则不是构造函数的功能。在定义对象数组的时候,就已经为对象数组分配了一定的存储空间。
若调用默认构造函数,则直接对数组对象相应空间的值进行初始化(一次构造,一次析构);若调用其他构造函数(非默认构造函数),则先建立一个临时对象,对其进行初始化,完成之后将临时空间的值拷贝到数组对象的相应空间中,然后执行临时对象的析构函数(一次构造,两次析构)。
不知道实际情况是不是这个样子。
非也
【 在 epeeist 的大作中提到: 】
: 我后来又想了想,不知道是否可以这样解释:
: 构造函数的作用只是对对象的值进行初始化,而为对象分配空间则不是构造函数的功能。在定义对象数组的时候,就已经为对象数组分配了一定的存储空间。
: 若调用默认构造函数,则直接对数组对象相应空间的值进行初始化(一次构造,一次析构);若调用其他构造函数(非默认构造函数),则先建立一个临时对象,对其进行初始化,完成之后将临时空间的值拷贝到数组对象的相应空间中,然后执行临时对象的析构函数(一次构造,两次析构)。
: ...................
创建一个对象分两步:
1.分配内存(stack or heap)
2.调用构造函数
使用=初始化对象,调用构造函数初始化的方式有两种可能,依编译器不同:
1.直接调用相应构造函数Student(int num, string name, char sex);
2.先创建一个临时对象,调用相应构造函数,然后使用重载的赋值操作符(不是拷贝构造函数)赋值对象
Dev_c++(gcc)为1
所以程序结果会是:
Constructorlisa
//Destructorlisa(无此输出,因为无临时对象,直接调用构造函数)
DefaultConstructor
num: 1002
name: lisa
sex: F
num: 1001
name: Brian
sex: M
DestructorBrian
Destructorlisa
lz应该用的是vs,vs的方法是2,先获得内存,然后创建临时对象,然后赋值
(如果不想编译器这样处理,可以不用等号赋值初始化)
所以是:
Constructorlisa
Destructorlisa (临时对象赋值后析构)
DefaultConstructor
num: 1002
name: lisa
sex: F
num: 1001
name: Brian
sex: M
DestructorBrian
Destructorlisa
【 在 flyingmiao 的大作中提到: 】
: 创建一个对象分两步:
: 1.分配内存(stack or heap)
: 2.调用构造函数
: ...................
正解,Student stud[2]调用两次默认构造函数, Student(1002, "lisa", 'F'), 调用构造函数,把对象复制到stud[0],随后销毁了
【 在 flyingmiao 的大作中提到: 】
: 创建一个对象分两步:
: 1.分配内存(stack or heap)
: 2.调用构造函数
: ...................
我个人觉得对vs编译器解释得不是很对
先给一个例子吧
源代码
class Construtor
{
public:
Construtor(void){cout<<"defalut"<<endl;}
Construtor(int a){cout<<"construtor with int param"<<endl;}
Construtor(const Construtor& c){cout<<"copy construtor"<<endl;}
Construtor& operator= (const Construtor& c){cout<<"= construtor"<<endl;}
~Construtor(){cout<<"deconstrutor"<<endl;}
};
int main(void)
{
Construtor con[2] =
{
Construtor(1002),
};
return 0;
}
vs2005编译运行结果
construtor with int param
defalut
deconstrutor
deconstrutor
编译器并没有产生临时对象,该程序的运行过程应该是
对象数组分配内存 ,然后直接在该片内存上面使用含参和默认构造函数进行构造
ps:在定义对象时使用=号其实调用的是拷贝构造函数而不会是=重载操作符
例如
Construtor c;
Construtor copy = c;
运行结果
defalut
copy construtor
deconstrutor
deconstrutor
还有一个有趣的现象没分析出来
将STL中的string类改为char*之后,发现输出结果和我上面分析的就一摸一样了
Constructorlisa
DefaultConstructorBrian
DestructorBrian
Destructorlisa
(省略了display())
附上原来的输出结果,同样省略了display
Constructorlisa
copy constructorlisa
Destructorlisa
DefaultConstructorBrian
DestructorBrian
Destructorlisa
大家继续分析吧
我来分析下为什么会出现楼上说的:将STL中的string类改为char*之后,发现输出结果和我上面分析的就一摸一样了这种情况。欢迎批评~~~
在c++中有四中情况下编辑器会为一个类生成默认构造函数。其中一种就是如果一个类A包含了一个类B做为自己的成员变量,并且B有自己的构造函数。这时如果A没有自己的构造函数,那么编辑器会为A生成一个无能的(呵呵,翻译有点问题有兴趣的可以看看英文)默认构造函数。在此处因为class Student 有一个string类为自己的成员变量,那么会强迫编辑器调用class Student的构造函数(此构造函数不是编辑器为class Student生成的,而是调用class Student内定义的带参数的构造函数,因为你已经为它写了带参数的构造函数)生成一个临时变量。
赞
to Lynus:我印象中调用拷贝构造函数还是重载赋值操作符是依实现而异的,都可以,primer plus里也是这么说的,原文:
StringBad metoo = knot;
metoo是一个新创建的对象,被初始化为knot的值,因此使用复制构造函数。但是,实现也可能分两步来处理:使用复制构造函数创建一个临时对象,然后通过=操作符将临时对象的值复制到新对象中。
------------------
这就是说:初始化一个对象总是会调用复制构造函数,而使用=操作符时也可能会调用赋值操作符
------------------
to feifei:
没有看懂string的构造和产生临时对象有什么必然的联系,哪本书里有说?找来看看,呵呵。
感觉c++很多细节太繁琐而模糊,让我有种cpp标准不完善的感觉
【 在 flyingmiao (amiao) 的大作中提到: 】
: 赞
: to Lynus:我印象中调用拷贝构造函数还是重载赋值操作符是依实现而异的,都可以,primer plus里也是这么说的,原文:
: StringBad metoo = knot;
: metoo是一个新创建的对象,被初始化为knot的值,因此使用复制构造函数。但是,实现也可能分两步来处理:使用复制构造函数创建一个临时对象,然后通过=操作符将临时对象的值复制到新对象中。
不存在后面的假设,标准都规定了只用复制构造函数
: ------------------
: 这就是说:初始化一个对象总是会调用复制构造函数,而使用=操作符时也可能会调用赋值操作符
: ------------------
: to feifei:
: 没有看懂string的构造和产生临时对象有什么必然的联系,哪本书里有说?找来看看,呵呵。
: 感觉c++很多细节太繁琐而模糊,让我有种cpp标准不完善的感觉