BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / soft-design / #22328同步于 2007/11/17
该镜像源已超过 30 天没有更新,可能在源站已被删除。
SoftDesign机器人发帖

[求助]C++中有关对象数组的初始化与构造函数的问题

epeeist
2007/11/17镜像同步9 回复
先是一段程序: //声明类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]会只调用一次构造函数,却调用两次析构函数?具体的数组创建过程是什么? 请达人指点迷津!多谢~~~
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
Jarod机器人#1 · 2007/11/18
【 在 epeeist 的大作中提到: 】 C++ Primer Plus的解释是: 初始化对象数组的方案是,首先使用默认构造函数创建数组元素,然后花括号中的构造函数将创建临时对象,然后将临时对象的内容复制到相应的元素中。 ~~~~~~~~~~~~ 这里复制应该是指 用拷贝构造函数复制到元素中的。所以还是有两次构造的
epeeist机器人#2 · 2007/11/19
我后来又想了想,不知道是否可以这样解释: 构造函数的作用只是对对象的值进行初始化,而为对象分配空间则不是构造函数的功能。在定义对象数组的时候,就已经为对象数组分配了一定的存储空间。 若调用默认构造函数,则直接对数组对象相应空间的值进行初始化(一次构造,一次析构);若调用其他构造函数(非默认构造函数),则先建立一个临时对象,对其进行初始化,完成之后将临时空间的值拷贝到数组对象的相应空间中,然后执行临时对象的析构函数(一次构造,两次析构)。 不知道实际情况是不是这个样子。
vivin机器人#3 · 2007/11/20
非也 【 在 epeeist 的大作中提到: 】 : 我后来又想了想,不知道是否可以这样解释: : 构造函数的作用只是对对象的值进行初始化,而为对象分配空间则不是构造函数的功能。在定义对象数组的时候,就已经为对象数组分配了一定的存储空间。 : 若调用默认构造函数,则直接对数组对象相应空间的值进行初始化(一次构造,一次析构);若调用其他构造函数(非默认构造函数),则先建立一个临时对象,对其进行初始化,完成之后将临时空间的值拷贝到数组对象的相应空间中,然后执行临时对象的析构函数(一次构造,两次析构)。 : ...................
flyingmiao机器人#4 · 2007/11/21
创建一个对象分两步: 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
wakaka007机器人#5 · 2007/11/27
【 在 flyingmiao 的大作中提到: 】 : 创建一个对象分两步: : 1.分配内存(stack or heap) : 2.调用构造函数 : ................... 正解,Student stud[2]调用两次默认构造函数, Student(1002, "lisa", 'F'), 调用构造函数,把对象复制到stud[0],随后销毁了
Lynus机器人#6 · 2007/11/27
【 在 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 大家继续分析吧
buptfeifei机器人#7 · 2007/11/30
我来分析下为什么会出现楼上说的:将STL中的string类改为char*之后,发现输出结果和我上面分析的就一摸一样了这种情况。欢迎批评~~~ 在c++中有四中情况下编辑器会为一个类生成默认构造函数。其中一种就是如果一个类A包含了一个类B做为自己的成员变量,并且B有自己的构造函数。这时如果A没有自己的构造函数,那么编辑器会为A生成一个无能的(呵呵,翻译有点问题有兴趣的可以看看英文)默认构造函数。在此处因为class Student 有一个string类为自己的成员变量,那么会强迫编辑器调用class Student的构造函数(此构造函数不是编辑器为class Student生成的,而是调用class Student内定义的带参数的构造函数,因为你已经为它写了带参数的构造函数)生成一个临时变量。
flyingmiao机器人#8 · 2007/12/2
赞 to Lynus:我印象中调用拷贝构造函数还是重载赋值操作符是依实现而异的,都可以,primer plus里也是这么说的,原文: StringBad metoo = knot; metoo是一个新创建的对象,被初始化为knot的值,因此使用复制构造函数。但是,实现也可能分两步来处理:使用复制构造函数创建一个临时对象,然后通过=操作符将临时对象的值复制到新对象中。 ------------------ 这就是说:初始化一个对象总是会调用复制构造函数,而使用=操作符时也可能会调用赋值操作符 ------------------ to feifei: 没有看懂string的构造和产生临时对象有什么必然的联系,哪本书里有说?找来看看,呵呵。 感觉c++很多细节太繁琐而模糊,让我有种cpp标准不完善的感觉
Yandere机器人#9 · 2007/12/2
【 在 flyingmiao (amiao) 的大作中提到: 】 : 赞 : to Lynus:我印象中调用拷贝构造函数还是重载赋值操作符是依实现而异的,都可以,primer plus里也是这么说的,原文: : StringBad metoo = knot; : metoo是一个新创建的对象,被初始化为knot的值,因此使用复制构造函数。但是,实现也可能分两步来处理:使用复制构造函数创建一个临时对象,然后通过=操作符将临时对象的值复制到新对象中。 不存在后面的假设,标准都规定了只用复制构造函数 : ------------------ : 这就是说:初始化一个对象总是会调用复制构造函数,而使用=操作符时也可能会调用赋值操作符 : ------------------ : to feifei: : 没有看懂string的构造和产生临时对象有什么必然的联系,哪本书里有说?找来看看,呵呵。 : 感觉c++很多细节太繁琐而模糊,让我有种cpp标准不完善的感觉