0

C++ 构造函数和析构函数(Constructors & Destructors) - 阮春义

 2 weeks ago
source link: https://www.cnblogs.com/ruanchunyi/p/18173186
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

C++ 构造函数和析构函数(Constructors & Destructors)

一、定义:

  当object产生,有一个特殊的称为constructor的函数会自动执行。当object死亡,有一个特殊的称为destructor的函数会自动执行。Constructor 可以不只一个,但 destructor 只能有一个。

  Constructor(构造函数)就是与class同名的那些member functions,例如CPoint::CPoint()或CDemo::CDemo()。Constructors不能够指定返回值类型,也就是它不必(但可以)return。constructions可以有一个或多个,各有不同类型的参数。

  Destructor(析构函数)就是与class同名,且前面有加“~”符号的那个member function,例如例如 CPoint::~CPoint() 或 CDemo::~CDemo()。Destructor 不能指定返回值类型,也就是它不必(但可以)return。每个class只有一个destructor,并且不能有任何参数。

  由于global object的诞生比程序进入更早点,所以global object的constructor执行的时间更早于程序的进入点。

二、Default Constructors

所谓的default constructor就是没有指定任何的参数的constructor。如果我们的class CA声明如下:

 1 #include <iostream>
 2 using namespace std;
 3 class CA
 4 {
 5  public:
 6     int getdata(){return _data;};
 7     CA(){_data =5;};
 8     CA(int val){_data =val;};
 9     
10  protected:
11     int _data; 
12     
13 };

  CA有两个constructors,分别是CA(int) 和 CA()。后都没有参数,正是所谓的default constructor。当我产生一个 CA object 而沒有指定任何参数:

1 CA aCA;
2 CA* pCA = new CA;

  编译器就为我们呼叫default constructor。

  普遍存在于C++程序员之间的一个误解是:如果我们没有为某个class设计constructor,编译器会自动为该class制造出一个default constructor来。这个说法也对也不对,这里我先提示一个结论,销稍后有更多细节探讨。什么是编译器所需要的动作?就是隐藏在C++程序代码下面,让C++诸多特征得到实现的动作,包含以下三种情况:

1447648-20240503150004575-757870298.png

  1. class CA 內 含 class CZ objects,如图1:当产生一个CA object 时,隐藏在底层的必要动作是先初始化CZ object(因为CA object中有一个CZ object)

  2.class CA继承于class CZ,如图2:当产生一个CA object 时,隐藏在底层的必要动作是先调用CZ的default constructor (因为CA object中有一个CZ subobject)

  3.CA是一个 polymorphic class,也就是说它有virtual functions,或继承于有virtual functions的class。当产生一个CA object,隐藏在底层的必要动作是:将虚拟机制所需要的vptr和vtb1初始化。

  由于这三种情况皆有所谓的“底层的必要动作”,所以编译器必须自动为class CA生成一个default constructor((如果沒有任何 user-defined constructor 的话),或暗中对已有的user-defined constructor 动作脚(添加一些代码)。生成出来的东西称为“implicit nontrivial default constructor”。

  如果沒有上述需求,编译器就不会为class产生一个default constructor,例如: 

1 class CB
2 { public:
3 int getdata() { return _data; };
4 protected:
5 int _data;
6 };

virtual functions的base classes),也没有内含embedded objects,也没有继承于其它class,所以编译器不会为它生成一个default constructor出来,于是当我们这么做:

1 CB aCB; // 应该调用default constructor
2 cout << "aCB.getdata()=" << aCB.getdata() << endl;

  但得到的结果如下:

aCB.getdata()=4211382 // 莫名其妙的初值

  这个恐怕不是我所期望的,我们期望的_data有个初始值,但这个不是编译器的需求,所以我们只能自求多福,自已设计一个default constructor:

1 class CB
2 { public:
3     int getdata() { return _data; };
4     CB() { _data = 5; }; // default constructor
5 protected:
6     int _data;
7 };

  现在输出的结果就是我们所期望的了:

CB aCB; // 应该调用  default constructor
cout << "aCB.getdata()=" << aCB.getdata() << endl;
// 输出结果:aCB.getdata()=5

  注意,如果class已经有了任何constructor,但不是default constructor,编译器绝不会为它生成一个default constructor。如果class CZ正是如此一个class,那么当你想产生一个CZ object,并且没有指定参数时:

CZ *aCZ; // error

  编译器会输出异常提示:

error C2512: 'CZ' : no appropriate default constructor available

三、Copy Constructors

  所谓的Copy Constructors是指有一个参数的类型是其 class type的 constructor,例如:

 1 class CA
 2 {
 3 public:
 4     int getdata() {return _data; };     //default constructor
 5     CA(){_data =5;};
 6     CA(int val){_data=val; };           //constructor
 7     CA(const CA& ca){                  //copy constructor
 8         cout<<"copy constructor"<<endl;
 9         _data=10;
10 
11     };
12 
13 protected:
14     int _data;
15 };

   以下两种情况,会唤起copy constructor:

  情况1:将一个object当做参数传给某一个函数;

  情况2:将一个object当做函数的返回值;

  例如(沿用上面的class CA):

 1 #include <iostream>
 2 
 3 using namespace std;
 4 class CA
 5 {
 6 public:
 7     int getdata() {return _data; };     //default constructor
 8     CA(){_data =5;};
 9     CA(int val){_data=val; };           //constructor
10     CA(const CA& ca){                  //copy constructor
11         cout<<"copy constructor"<<endl;
12         _data=10;
13 
14     };
15 
16 protected:
17     int _data;
18 };
19 
20 void foo2(CA aCA)//情况1(函数参数是个object)
21 {
22     cout<<"in foo2(),aCA.getdata()="<<aCA.getdata()<<endl;
23 }
24 
25 CA foo3()//情况2(函数的返回值是个object)
26 {
27     CA aCA(3);
28     cout<<"in foo3(),aCA.getdata()="<<aCA.getdata()<<endl;
29     return aCA;
30 }
31 
32 int main()
33 {
34 
35     CA aCA1,aCA2(7);
36     cout << "aCA1.getdata()="<<aCA1.getdata()<< endl;
37     cout << "aCA2.getdata()="<<aCA2.getdata()<< endl;
38     aCA2 =aCA1;//object assignment
39     cout << "aCA2.getdata()="<<aCA2.getdata()<< endl;
40     foo2(aCA1);//情况1(调用之前aCA1._data 为5)
41     aCA2=foo3();
42     cout << "aCA2.getdata()="<<aCA2.getdata()<< endl;
43 
44     return 0;
45 }

  让我们看看执行结果:

aCA1.getdata()=5
aCA2.getdata()=7
aCA2.getdata()=5 // 经过 object assignment 之后
copy constructor
in foo2(), aCA.getdata()=10 // 经过情況 1 之后
in foo3(), aCA.getdata()=3
copy constructor
aCA2.getdata()=10 // 经过情況 2 之后

  这里有几点需要注意的:

  1. 38行的将一个object指派(assign)给另一个object,这也是一种复制,但它唤起的所谓的copy assignment operator。本例并没有特别设计copy assignment operator;

  2.调用foo2()之前,_data为5,进入foo2()之后再输出,已变成10,可见copy constructor的确在foo2()的参数复制时发生;

  3.foo3()内有一个local object,其_data为3,把穹当做返回值输出,却变成了10,可见copy constructor的确在foo3()的返回值复制时发生;


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK