问题 1:
C++ 中的类能够定义多个对象,那么对象构造的顺序是怎样的?编程
问题 2:
对象构造顺序会带来什么影响呢?函数
对象构造每每与构造函数相关联,构造函数体有多是很是复杂的程序逻辑组成,不一样类的构造函数中程序逻辑多是相互依赖的。当相互依赖发生时,对象的构造顺序就变得尤其重要。
对于局部对象(包含静态局部对象)code
- 当程序执行流到达对象的定义语句时进行构造
下面程序中的对象构造顺序是什么?对象
void code() { int i = 0; Test a1 = i; while( i < 3) Test a2 = ++i; if( i < 4 ) { Test a = a1; } else { Test a(100); } }
test_1.cppget
#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("const Test& obj : %d\n", mi); } }; int main() { int i = 0; Test a1 = i; while( i < 3) Test a2 = ++i; if( i < 4 ) { Test a = a1; } else { Test a(100); } return 0; }
输出: Test(int i) : 0 Test(int i) : 1 Test(int i) : 2 Test(int i) : 3 const Test& obj : 0 结论: 局部对象的构造顺序与程序的执行流相关
error.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("const Test& obj : %d\n", mi); } int getMi() { return mi; } }; int main() { int i = 0; Test a1 = i; while( i < 3) Test a2 = ++i; goto End; // 注意这里! Test a(100); End: printf("a.mi = %d\n", a.getMi()); return 0; }
g++ 输出: test.cpp:30: error: jump to label ‘End’ test.cpp:28: error: from here test.cpp:29: error: crosses initialization of ‘Test a’ vc2010 编译输出: error.cpp(34) : warning C4533: “goto a”跳过了“End”的初始化操做 error.cpp(33) : 参见“a”的声明 error.cpp(34) : 参见“End”的声明 vc2010 运行输出: Test(int i) : 0 Test(int i) : 1 Test(int i) : 2 Test(int i) : 3 a.mi = 4076341
发生了什么?it
对于堆对象io
- 当程序执行流到达 new 语句时建立对象
- 使用 new 建立对象将自动触发构造函数的调用
下面程序中的对象构造顺序是什么?编译
void code() { int i = 0; Test* a1 = new Test(i); while( ++i < 10 ) if( i % 2 ) new Test(i); if( i < 4 ) new Test(*a1); else new Test(100); return 0; }
#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("const Test& obj : %d\n", mi); } int getMi() { return mi; } }; // 这里在 new 以后没有 delete,仅为演示 int main() { int i = 0; Test* a1 = new Test(i); while( ++i < 10 ) if( i % 2 ) new Test(i); if( i < 4 ) new Test(*a1); else new Test(100); return 0; }
输出: Test(int i) : 0 Test(int i) : 1 Test(int i) : 3 Test(int i) : 5 Test(int i) : 7 Test(int i) : 9 Test(int i) : 100 结论: 堆对象的构造顺序与程序的执行流相关。堆对象一样受到程序执行流的影响,具体可参考局部对象中的分析。
对于全局对象class
- 对象的构造顺序是不肯定的
- 不一样的编译器使用不一样的规则肯定构造顺序
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");
test.cpp
#include "test.h" Test t4("t4"); int main() { Test t5("t5"); return 0; }
g++ 输出: t3 t2 t1 t4 t5 vc2010 输出: t4 t1 t2 t3 t5
警示: 尽可能避开全局对象,尽可能避开全局对象的相互依赖
- 局部对象的构造顺序依赖于程序的执行流
- 堆对象的构造顺序依赖于 new 的使用顺序
- 全局对象的构造顺序是不肯定的
以上内容参考狄泰软件学院系列课程,请你们保护原创!