C++面向對象-2-類的構造函數和析構函數

上一篇學習了C++中的類定義,用了兩個練習題來演示一個class的屬性和行爲的定義和調用,以及展開了權限控制和一個類的屬性還可以是其他類的一個實例。其中有好多代碼是set和get, 寫多了有時候很煩,當然寫set和get方法是一個好習慣。例如Point,我們需要setX和setY, 有沒有一個方法直接SetPoint(X,Y)呢, 這個就本篇要學習的類的構造函數。

 

區別:struct vs class

在學習構造函數之前,我們先學習一下C++中struct和class的區別,在C中struct是結構體,class和struct幾乎沒有區別,如果你不想使用class去寫一個類,當然可以使用struct去寫相關代碼。簡單來說,struct中的屬性默認是public, 而class中的屬性默認是private的,下面用代碼來證明一下。

#include <iostream>
using namespace std;

struct A
{
    int a;
};

class B
{
    int b;
};

int main()
{
    A a1;
    a1.a = 100;

    B b1;
    b1.b = 100;
    system("pause");
    return 0;
}

不需要運行上面代碼,在b1.b這個位置,IDE會報錯,提示 11行不可以訪問,原因如下:

在struct中,屬性的權限默認是public, 在class中屬性的權限默認是private, 行爲也是一樣。

 

構造函數

在C++中,類的構造函數會在類初始化的過程中就會執行構造函數。我們希望在一個類初始化的時候,就給這個類的屬性進行設置初始化值,在C++中通過構造函數來實現。格式是這樣的

class Point
{
    //構造函數
    Point()
    {

    }

private:
    int X;
    int Y;
};

構造函數的特點,函數名稱和類的名稱相同,前面沒有返回值,可以有參數,也可以無參數。有參加就叫有參構造,無參數就叫無參構造。上面就是一個無參構造,主要我們定義了一個類,如果我們沒有寫這個無參構造,編譯器在編譯和運行代碼的時候會自動給我們添加這個無參構造(空實現)。如果我們在定義類的時候,寫了有參構造,編譯器不會自動幫我們添加無參構造,建議我們自己寫代碼的時候,自己添加有參和無參構造函數。

下面代碼來證明,類在初始化的時候,調用了構造函數,以下用無參構造函數演示。

#include<iostream>
using namespace std;

class Point
{

public:

    //構造函數
    Point()
    {
	cout << "調用了構造函數"<< endl;
    }

private:
    int X;
    int Y;
};

int main()
{
    Point p;
    system("pause");
    return 0;
}

執行結果

總結:

構造函數語法:類名(){}
1.構造函數,沒有返回值也不寫void
2.函數名稱與類名相同
3.構造函數可以有參數,因此可以發送重載
4.程序在調用對象的時候會自動調用構造函數。

 

析構函數

和類初始化相反的事情叫事後清理,在C++中,採用析構函數來實現類的運行結束前的清理操作。

析構函數語法:~類名(){}
1.析構函數,沒有返回值也不寫void
2.函數名稱與類名相同,在名稱前面加上符號~
3.析構函數不可以有參數,因此不可以發送重載
4.程序在對象銷燬前會自動調用析構函數,無需手動調用而且只會調用一次

在上面構造函數基礎上,添加析構函數的代碼

#include<iostream>
using namespace std;

class Point
{

public:

    //構造函數
    Point()
    {
	cout << "調用了構造函數"<< endl;
    }

    //析構函數
    ~Point()
    {
	cout << "調用了析構函數" << endl;
    }

private:
    int X;
    int Y;
};

int main()
{
    Point p;
    system("pause");
    return 0;
}

運行這個看起來並沒有打印調用了析構函數,實際上是在輸入任意鍵的一瞬間打印了調用析構函數。因爲main函數是在內存的全局區,運行到system("pause"); 這裏,我們main函數並沒有結束,所以這個時刻的Point p這個對象沒有結束,自然沒有調用析構函數,但是執行return 0的一瞬間應該打印了析構函數的調用。爲了看到打印效果,我們把類初始化代碼放到一個內存代碼局部區去。

#include<iostream>
using namespace std;

class Point
{

public:

    //構造函數
    Point()
    {
	cout << "調用了構造函數"<< endl;
    }

    //析構函數
    ~Point()
    {
	cout << "調用了析構函數" << endl;
    }

private:
    int X;
    int Y;
};

void test01()
{
    Point p;
}

int main()
{
    test01();
    system("pause");
    return 0;
}

運行結果:

在main()方法執行到test01()的時候,調用了test01()裏面的Point p, 這個時候執行了Point類的初始化和清理操作,因爲test01()執行完就從main()方法中彈出棧,Point p就從內存中回收,所以回收內存之前編譯器自動調用了析構函數,所以能看到打印效果。

 

       構造函數分類:安裝是否帶參數,可以分無參構造和有參構造,按照類型分普通構造和拷貝構造,關於這個分類和構造函數的調用方法,下一篇來介紹。本篇學習了構造函數和析構函數,構造函數的作用是類初始化過程運行一次,給屬性設置初始化值。析構函數的作用是,在類銷燬之前執行一些操作,也只調用一次。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章