c++构造函数以及类中变量初始化顺序
来源:互联网 发布:淘宝修身包臀连衣裙 编辑:程序博客网 时间:2024/06/05 23:47
c++构造函数以及类中变量初始化顺序
构造函数
c++ 的类提供了一种抽象机制,使用起来要比 c 方便很多。为了安全等,c++ 中的每一个对象都要经过构造,跑出作用域之外的对象(非 free-store 上的)都要析构,不管是使用自定义的构造/析构函数也好,还是使用默认的。为了对象的正确拷贝构造或是赋值,me 们要自己写拷贝构造函数/拷贝赋值,为了所谓的效率,还得自己写移动构造函数/移动赋值。默认生成的若干个函数有:
Test(); // 默认构造函数,可以不带参数的构造函数,T t;Test(Test& t); // 拷贝构造函数,T t2 = t;Test(Test&& t); // 移动构造函数,T t3 = fun(); fun() 返回一个 T 的临时对象Test& operate=(Test& t); // 拷贝赋值,t3 = t2;Test& operate=(Test&& t); // 移动赋值,t2 = fun();~Test(); // 析构函数
默认构造函数比较简单,两个移动 (move) 函数是 c++11 中加入的,其实也可以先不关心,拷贝赋值也先不关心,就说拷贝构造函数,神马时候会调用的问题,根据 wiki 的说法:
- 直接使用一个对象构造一个对象,如 T t2 = t; 或是 T t2(t);
- 将一个对象以值(不是引用)的形式递给一个函数,比如 test(t);
- 将函数中的一个对象的值(不是引用)传递出函数外,比如 fun();
- throw 一个对象,catch 一个对象的值(不是引用);
基本规则是上面说的,但是却不是总是那样,据说 c++标准允许编译器优化拷贝,实际上 gcc 在函数返回值是否拷贝的问题上很多时候跟 vc++ 就不一致。有一项技术叫 RVO (return value optimization ) —— 返回值优化,貌似就是说的那个。me 的实际运行结果是:gcc 在函数返回一个对象的值的时候可能不调用拷贝构造函数/移动构造函数,而 vc++ 就要循规蹈矩得多一些,虽然说是数据多拷了几次。真的是 maybe,即使是 vc++ 在函数中直接 return T(); 和 Test t; return t; 结果都可能不一样,gcc 中的结果可能更离奇一点。
很多时候真不用关心这一点细节问题,拷贝也不会出什么问题。不过拷贝构造 maybe 有“副作用”,比如不是等值拷贝,而是放大一倍拷贝,这个时候,如果拷贝构造函数调用的次数都不一样,程序结果可能就不一样,实际上是,结果的确就不一样!所以,拷贝还是尽可能遵循原有的“语义”,等值拷贝,否则都是合法的 c++程序,在 vc 和 gcc 中结果不一样让人有些惊讶!
现在说,移动构造的问题,可以先看下右值引用。有了移动构造的话,有时候就影响拷贝构造,比如 T t=fun(); 以前肯定会说是调用“拷贝构造函数”,现在就不一定了,可能就是“移动构造函数”了,也就是直接将返回来的临时对象,作为新构造的对象使用;而按其那面 gcc 的逻辑,可能这里神马“构造函数”都不调用,因为就没有构造!如果说对于 A a = testA(); 会调用“移动构造”,而 B b = testB(); 却不调用“移动构造”,这也令 me 很震惊,都是返回一个临时对象,都有移动构造函数,为嘛有时候就调用,有时候就不调用?O__O"…竟然跟里面是神马变量有关?!!!可以修改下面的程序,自己看运行结果:(移动构造是 c++11 新加的,gcc 编译的话,需要加上 -std=c++11,or =std=c++0x)。
- #include <iostream>
- using namespace std;
- class Test{
- public:
- Test(){ value = 0; cout << "default constructor." << "\n"; }
- Test(Test& t){ value = 42; cout << "non-const copy constructor." << "\n"; } // can modify t.value !
- Test(const Test& t){ cout << "const copy constructor." << "\n"; }
- Test(Test&& t): value(t.value){ cout << "move constructor." << "\n"; }
- ~Test(){ cout << "destructor." << "\n"; }
- int getValue(){ return value; };
- private:
- int value;
- };
- Test fun(Test tmp)
- {
- Test a;
- return a;
- }
- int main()
- {
- Test a;
- cout << "a.value:" << a.getValue() << "\n";
- Test b = fun(a);
- cout << "b.value:" << b.getValue() << "\n";
- Test c = a;
- cout << "c.value:" << c.getValue() << "\n";
- return 0;
- }
类中变量的初始化顺序
c++ 中类变量的初始化顺序,大体如下:
- 基类的静态成员初始化;
- 派生类的静态成员初始化;
- 基类的对象成员初始化;
- 基类的构造函数;
- 派生类的对象成员初始化;
- 派生类的构造函数;
貌似 c++11 允许类中变量直接初始化,跟 Java 的使用方法类似,me 么试过。其次,类中对象成员的初始化顺序跟构造函数中初始化列表的顺序无关,只跟声明时候的顺序有关。
测试程序:
- #include <iostream>
- using namespace std;
- class Inner{
- public:
- Inner(int i=0): in(i) { cout << "Inner.constructor." << "\n";}
- Inner(Inner& inner): in(inner.in) { cout << "Inner.copy consturctor" << "\n";};
- int getValue(){ return in; }
- private:
- int in;
- };
- class Inner2{
- public:
- Inner2(double i=0.0): in2(i) { cout << "Inner2.constructor." << "\n";}
- Inner2(Inner2& inner2): in2(inner2.in2) { cout << "Inner2.copy consturctor" << "\n";};
- int getValue(){ return in2; }
- private:
- double in2;
- };
- class Base{
- public:
- Base(int v=0): value(v) { value = 1; cout << "Base.constructor." << "\n";}
- Base(Base& b): value(b.value) { cout << "Base.copy consturctor" << "\n";}
- int getValue(){ return value; }
- protected:
- int value;
- };
- class Derive: public Base{
- public:
- // Derive(string s = "hello", int base=0, int i=0, double i2=0): derive(s), in2(i2), in(i) { cout << "derive.derive == " << derive << ", Derive.consturctor" << "\n";};
- Derive(string s = "hello", int base=0, int i=0, double i2=0){ cout << "Derive.consturctor" << "\n";};
- Derive(Derive& d): derive(d.derive) { cout << "Derive.copy consturctor" << "\n";}
- void printValue(){ cout << "derive.base.value == " << value << ", derive.derive == " << derive << ", derive.in == " << in.getValue() << ", derive.in2 == " <<in2.getValue() << "\n"; }
- private:
- string derive;
- Inner in;
- Inner2 in2;
- };
- int main()
- {
- Derive d("world", 10, 20, 30.0);
- d.printValue();
- // Derive d2 = d;
- cout << endl;
- }
- c++构造函数以及类中变量初始化顺序
- static 变量和static 构造函数 以及对象初始化顺序
- 构造函数中成员变量初始化顺序问题
- C++中构造函数、析构函数以及类成员初始化顺序详解
- 构造函数和变量初始化顺序
- 类的成员变量 声明顺序 决定 初始化顺序(构造函数初始化列表不影响)
- 构造函数初始化、static代码块初始化、成员变量初始化、以及在子父类中混合的执行顺序实例
- Java类初始化顺序问题:静态初始化块,非静态初始化块以及构造函数
- Java 代码块、成员变量初始化、构造函数初始化顺序
- [C++]类成员冒号初始化以及构造函数内赋值
- 关于类继承/初始化成员变量/构造函数/析构函数 执行顺序
- 关于类继承/初始化成员变量/构造函数/析构函数 执行顺序
- 关于类继承/初始化成员变量/构造函数/析构函数 执行顺序
- Java中静态代码块、非静态代码块以及构造函数的初始化顺序
- java变量,初始化快,构造函数的执行顺序
- java变量,初始化快,构造函数的执行顺序
- java变量,初始化快,构造函数的执行顺序 .
- 构造函数及其成员变量初始化顺序详解
- caffe学习
- FILE* fp
- arm-linux-gnueabi-gcc编译uboot出错
- [HTML]显示/隐藏DIV的技巧(visibility与display的差别)
- iOS ZipArchive
- c++构造函数以及类中变量初始化顺序
- sysfs API总结
- 【创客笔记】:慎用BAT的人
- niagara编程中需要注意的几点问题
- 建造者模式
- 云端观察:传统教育如何应对三大挑战?
- 安卓中sharepreference总结
- Ryan的OC学习总结-----6 块
- 心得与体会