第21课 对象的构造顺序
1. 对象的构造顺序
———C++中的类可以定义多个对象,那么对象构造顺序是怎样的?
(1)对于局部对象:当程序执行流到达对象的定义语句时进行构造
(2)对于堆对象
①当程序执行流到达new语句时创建对象
②使用new创建对象将自动触发构造函数的调用
(3)对于全局对象
①对象的构造顺序是不确定的
②不同的编译器使用不同的规则确定构造顺序
【实例分析】局部对象的构造顺序 21-1.cpp
#include <stdio.h> class Test { private: int mi; public: Test(int i) { mi = i; printf("Test(int i): %d\n", mi); } Test(const Test& obj) { mi = obj.mi; printf("Test(const Test& obj): %d\n", mi); } ~Test() { printf("~Test(): %d\n", mi); } }; int main() { int i = 0; Test a1 = i;//Test(int i):0,执行到这里时构造a1 while(i < 3) { //注意:a2的作用域只在这个大括号内 //所以,每执行1次,构造一次a2 Test a2 = ++i;//Test(int i):1、2、3 } goto LabelEnd; //因跳转,所以下列的a不会被构造 if (i < 4) { Test a = a1;//Test(const Test&):0。但因goto,该对象不会被构造 } else { Test a(100);//不会被执行,所以不会调用Test(int i) } LabelEnd: return 0; }
【编程实验】堆对象的构造顺序 21-2.cpp
#include <stdio.h> class Test { private: int mi; public: Test(int i) { mi = i; printf("Test(int i): %d\n", mi); } Test(const Test& obj) { mi = obj.mi; printf("Test(const Test& obj): %d\n", mi); } ~Test() { //printf("~Test(): %d\n", mi); } }; int main() { int i = 0; Test* a1 = new Test(i); //Test(int i):0 while(++i < 10) if (i % 2) //i % 2 !=0 new Test(i);//Test(int i):1、3、5、7、9 if (i < 4) { new Test(*a1);//Test(const& Test):0 } else { new Test(100);//Test(int i):100 } return 0; }
【实例分析】全局对象的构造顺序 21-3.cpp
//test.h
#ifndef _TEST_H_ #define _TEST_H_ #include<stdio.h> class Test { public: Test(const char* s) { printf("%s\n", s); } }; #endif
//t1.cpp
#include "test.h" 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");//全局变量 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)全局对象的构造顺序是不确定的