C++中构造函数,拷贝构造函数,析构函数

C++中默认构造函数就是没有形参的构造函数。准确的说法,按照《C++ Primer》中定义:只要定义一个对象时没有提供初始化式,就是用默认构造函数。为所有 的形参提供默认实参的构造函数也定义了默认构造函数。

合成的默认构造函数,即编译器自动生成的默认构造函数。《C++ Primer》中的说明:一个类哪怕只定义了一个构造函数,编译器也不会再生成默认构造函数。这条规则的根据是,如果一个类再某种情况下需要控制对象初始化,则该类很可能在所有情况下都需要控制。只有当一个类没有定义构造函数时,编译器才会自动生成一个默认构造函数。

需要注意的是自定义的构造函数包括拷贝构造函数。就是说在下面这种情况下,编译器也不会自动生成默认构造函数,代码会出错。把拷贝构造函数删除掉后就没有问题了。

编译器为类自动生成的函数包括默认构造函数,拷贝构造函数,析构函数,赋值函数。但是如果自己定义了拷贝构造函数,那么默认构造函数编译器就不会自动生成了。但是自己定义了默认构造函数时其他函数都会自动生成。

注意拷贝构造函数的参数类型为const Base &类型。&是必须的很容易理解,需要传递引用才行。至于const参数在g++中不加在编译时会报错,在vs中能通过编译。不过建议还是加上,因为传递的是引用,根据原对象构造新的对象时当然不希望将原对象改变。

#include <iostream>using namespace std;class Base{public://构造函数//Base(){//cout<<"default constructor invoke!"<<endl;//}//Base(int d){//this->data=d;//cout<<"constructor invoke!"<<endl;//}//拷贝构造函数Base(const Base &b){cout<<"copy constructor invoke!"<<endl;this->data=b.data;}//赋值操作符Base & operator=(const Base &b){cout<<"operator constructor invoke!"<<endl;this->data=b.data;}//7构函数~Base(){cout<<"deconstructor invoke!"<<endl;}private:int data;};int main(){Base b;return 0;}

首先使用下面的代码测试,默认构造函数,构造函数,拷贝构造函数,赋值操作符的调用:#include <iostream>using namespace std;class Base{public://构造函数Base(){cout<<"default constructor invoke!"<<endl;}Base(int d){this->data=d;cout<<"constructor invoke!"<<endl;}//拷贝构造函数Base(const Base &b){cout<<"copy constructor invoke!"<<endl;this->data=b.data;}//赋值操作符void operator=(const Base &b){cout<<"operator constructor invoke!"<<endl;this->data=b.data;}//析构函数~Base(){cout<<"deconstructor invoke!"<<endl;}private:int data;};int main(){Base b(1);//构造函数调用Base b2=b;//拷贝构造函数调用Base b3;//默认构造函数调用b3=b;//赋值操作符调用return 0;}执行结果如下:

在g++和vs中执行的结果都是一样的。

然后添加一个函数调用来测试:

#include <iostream>using namespace std;class Base{public://构造函数Base(){cout<<"default constructor invoke!"<<endl;}Base(int d){this->data=d;cout<<"constructor invoke!"<<endl;}//拷贝构造函数Base(const Base &b){cout<<"copy constructor invoke!"<<endl;this->data=b.data;}//赋值操作符void operator=(const Base &b){cout<<"operator constructor invoke!"<<endl;this->data=b.data;}//7构函数~Base(){cout<<"deconstructor invoke!"<<endl;}Base play(Base b){return b;}private:int data;};int main(){Base b(1);//构造函数调用Base b2=b;//拷贝构造函数调用Base b3;//默认构造函数调用b3=b;//赋值操作符调用b.play(2);//构造函数调用,拷贝构造函数调用(由于函数返回引起的)return 0;}结果如下:函数b.play(2)执行时,首先会使用构造函数(即接受一个int型变量的构造函数)进行隐式的类型转换,即调用一次构造函数。注意,如果play的形参是B&类型的话,就不可以这样做。否则会出错。

然后使用直接调用时:

#include <iostream>using namespace std;class Base{public://构造函数Base(){cout<<"default constructor invoke!"<<endl;}Base(int d){this->data=d;cout<<"constructor invoke!"<<endl;}//拷贝构造函数Base(const Base &b){cout<<"copy constructor invoke!"<<endl;this->data=b.data;}//赋值操作符void operator=(const Base &b){cout<<"operator constructor invoke!"<<endl;this->data=b.data;}//7构函数~Base(){cout<<"deconstructor invoke!"<<endl;}Base play(Base b){return b;}private:int data;};int main(){Base b(1);//构造函数调用Base b2=b;//拷贝构造函数调用Base b3;//默认构造函数调用b3=b;//赋值操作符调用b.play(2);//构造函数调用,拷贝构造函数调用(由于函数返回引起的)b.play(b);//<span style="font-size: 11.8181819915771px; font-family: Arial, Helvetica, sans-serif;">第一次拷贝构造函数调用是构造形参,第二次拷贝构造函数调用是函数返回值</span>return 0;}输出结构如下:

最开始也不明白为什么是两次拷贝构造函数调用。那么打印出每个对象的地址吧。

vs中的结果:

g++中的结果,可以发现g++中的结果参数进栈的顺序还是有规律的,但是vs好像就没有规律了。

离开你的那一天开始,左心房渐渐停止跳动…

C++中构造函数,拷贝构造函数,析构函数

相关文章:

你感兴趣的文章:

标签云: