好多bug由对象构造造成--------对象的构造与构造函数有关系
1. 对象的构造顺序
—C++中的类可以定义多个对象,那么对象构造顺序是怎样的?
(1)对于局部对象:当程序执行流到达对象的定义语句时进行构造。 对象定义--->构造---->调用构造函数
1 #include<stdio.h> 2 3 class Test 4 { 5 private: 6 int mi; 7 public: 8 Test(int i) //构造函数 9 { 10 mi = i; 11 printf("Test(int i) : %d ",mi); 12 } 13 Test(const Test& obj) //拷贝构造函数 14 { 15 mi = obj.mi; 16 printf("Test(const Test& obj) : %d ", mi); 17 } 18 19 /* 20 int getMi() 21 { 22 return mi; 23 } 24 */ 25 }; 26 27 int main() 28 { 29 int i = 0; 30 Test a1 = i; // 对象构造 Test(int i) :0 31 32 while (i < 3) 33 { 34 Test a2 = ++i; //对象的定义,那么就有对象构造3次 Test(int i) :1,2,3 35 } 36 37 if (i < 4) 38 { 39 Test a = a1; //对象的定义,那么就有对象拷贝构造 Test(const Test& obj) : 0 40 } 41 else 42 { 43 Test a(100); 44 } 45 46 /* 47 goto End; 不能非法改变程序的执行流 48 49 Test a(100); //a没有构造,初始化,后面不能使用 50 End: 51 printf("a.mi=%d ",a.getMi()); //没有初始化对象,没有调用构造函数,有的编译器会输出随机值 52 53 */ 54 return 0; 55 }
(2)对于堆对象
①当程序执行流到达new语句时创建对象
②使用new创建对象将自动触发构造函数的调用
1 #include<stdio.h> 2 3 //堆对象的构造顺序 Test* a1 = new Test(i); 4 5 class Test 6 { 7 private: 8 int mi; 9 public: 10 Test(int i) //构造函数 11 { 12 mi = i; 13 printf("Test(int i) : %d ", mi); 14 } 15 Test(const Test& obj) //拷贝构造函数 16 { 17 mi = obj.mi; 18 printf("Test(const Test& obj) : %d ", mi); 19 } 20 21 }; 22 23 int main() 24 { 25 int i = 0; 26 Test* a1 = new Test(i); //Test(int i) : 0 27 28 while (++i < 10) 29 if (i % 2) 30 new Test(i); //Test(int i) : 1,3,5,7,9 31 32 if (i < 4) 33 new Test(*a1); 34 35 else 36 new Test(100); //Test(int i) :100 37 38 return 0; 39 }
(3)对于全局对象
①对象的构造顺序是不确定的
②不同的编译器使用不同的规则确定构造顺序
//test.h
#ifndef _TEST_H_ #define _TEST_H_ #include<stdio.h> class Test { public: Test(const char* s) { printf("%s ", s); } }; #endif
//t1.cpp
Test t1("t1");//全局变量 //t2.cpp #include "test.h"
Test t2("t2");//全局变量 //t3.cpp #include "test.h"
Test t3("t3");//全局变量
//main.cpp
#include <stdio.h> #include "test.h" //注意:全局变量会先于main函数执行,因此 //4个全局变量t1-t4会被先构造,再其顺序是不确定的, //要依赖于编译器。 那么不同的编译器使用不同的规则确定全局变量的构造顺序 //当构造完全局对象后,会执行main函数,可以发现 //t5是最后一个被构造的。 Test t4("t4"); //全局变量 他的构造在main()之前 int main() { Test t5("t5"); //局部对象,他的构造按照程序执行流 return 0; }
g++编译器的输出结果:
//实验1:g++ main.cpp t1.cpp t2.cpp t3.cpp
//t3->t2->t1->t4->t5: 从右向左
//实验2:g++ t3.cpp t1.cpp main.cpp t2.cpp
//t2->t4->t1->t3->t5: 从右向左
2.小结
(1)局部对象的构造顺序依赖于程序的执行流
(2)堆对象的构造顺序依赖于new的使用顺序
(3)全局对象的构造顺序是不确定的