C++:構造函數,析構函數詳解

前言

上期瞭解C++類中有public、protected、private三種訪問權限。

肯定會有人疑惑,C++為什麼要設置這三個權限呢

本期內容就是圍繞上面的問題展開說明

一、面向對象

開始的文章就提到過,類是(OOP)面向對象編程的基礎

那麼面向對象編程究竟是個什麼東東呢

百度百科是這樣解釋的

在這裡插入圖片描述

通俗的來說就是利用代碼將現實世界的事物抽象出來,使代碼更具有真實事物的行為

簡單舉個栗子

狗是人類的朋友,有很多人養狗做寵物

寵物狗有名字,年齡,毛發顏色,等等特征

狗還會吃飯,喝水,汪汪汪之類的行為

如果利用代碼抽象一個小狗類

這些名字,年齡等就對應成員變量

吃飯喝水等行為就是成員函數

上代碼

class Dog
{
protected:
	int Age;
	string Name;
	string Color;
public:
	void Eating()
	{
		cout << "吃狗糧" << endl;
	}
	void Drinking()
	{
		cout << "喝水水" << endl;
	}
	void Wangwangwang()
	{
		cout << "汪汪汪!!!" << endl;
	}
};

在現實世界中狗的名字我們可以改,但年齡和顏色我們是無法改變的,就比如狗的顏色是它本身DNA決定的。我們可以分辨顏色是因為我們視力沒有問題,可以通過看的方式訪問狗的顏色

所以我們通常在代碼裡將成員變量設置成protected屬性

讓外部無法直接訪問,就像我們無法直接去看狗的DNA序列一樣。

所以通常會定義一些成員函數來間接訪問成員變量(這裡上期講解遺漏瞭,下面補充一下)

Protected和private無法在類外訪問,但可以在自己的類內部被成員函數訪問(對外接口)
而將這些成員函數放在public下,在類外使用這些成員函數,就相當於間接訪問無法訪問的變量
這就體現出C++面向對象中封裝的特性

我們看看百度百科中對封裝的介紹

在這裡插入圖片描述

簡單 的說,外部使用一個封裝好的類的時候隻會考慮某些接口的特定功能,而並不會關心內部的具體實現細節。

具體看下圖:

在這裡插入圖片描述

那麼進入主題,看看封裝的具體技術

二、構造函數

1.基本概念

基本概念:構造函數是類的成員函數,作用是在類創建對象時用於初始化對象。

特點:函數名和類名相同且不用寫返回值,在創建對象時會自動調用。

語法:函數名( 形參列表 ){ 函數實現 }

註意:

1.構造函數不需要返回值類型

2.構造函數的函數名和類名相同

在這裡插入圖片描述

代碼如下:

class MyClass
{
protected:
	int i;
	char c;
	string str;
public:
	void print()//用於顯示成員變量
	{
		cout << "i = " << i << endl;
		cout << "c = " << c << endl;
		cout << "str = " << str << endl;
	}
	MyClass()//構造函數
	{
		i = 5;
		c = 'a';
		str = "str in MyClass";
	}
};
void test()
{
	//創建對象  cla
	MyClass cla;
	//調用 成員函數print
	cla.print();
}
int main()
{
	test();
	return 0;
}

運行效果:

在這裡插入圖片描述

可見我們隻是創建瞭一個對象,並沒有對這個對象做任何操作。

我們不用自己調用構造函數,編譯器在創建對象時自動調用構造函數,為變量初始化。

2.構造函數重載

1.構造函數分類

構造函數大概分無參構造、有參構造、拷貝構造三種

上述代碼中的構造函數就是一個典型的無參構造

2.有參構造函數:

例如以下代碼:(有參構造的3個重載)

MyClass(int i)
{
	this->i = i;
}
MyClass(int i, char c)
{
	this->i = i;
	this->c = c;
}
MyClass(int i,char c,string str)
{
	this->i = i;
	this->c = c;
	this->str = str;
}

3.有參構造函數3個調用規則:

括號法:

//使用有參構造函數創建對象   cla2,cla3,cla4
MyClass cla2(10);
MyClass cla3(10, 'b');
MyClass cla4(10, 'b', "str in MyClass_cla2");

等號法:

//使用有參構造函數創建對象(等號法)
MyClass cla5 = 10;
MyClass cla6 = (10, 'b');

直接調用構造函數

//使用有參構造函數創建對象(調用構造函數)
MyClass cla7 = MyClass(10);
MyClass cla8 = MyClass(10, 'b');
MyClass cla9 = MyClass(10, 'b', "str in MyClass");

4.拷貝構造函數

MyClass(MyClass& cla)
{
	this->i = cla.i;
	this->c = cla.c;
	this->str = cla.str;
}

註意:拷貝構造函數的形參是自身類型的引用

拷貝構造函數調用

//使用拷貝構造函數創建對象
MyClass cla11(cla8);
MyClass cla12 = cla9;

5.析構函數

基本概念:在對象被釋放時編譯器會自動調用析構函數,用於釋放對象中變量的內存空間

語法:函數名( 形參列表 ){ 函數實現 }

註意:

1.構造函數不需要返回值類型

2.構造函數的函數名為 ~(類名)

特點:函數名和類名相同且不用寫返回值,在創建對象時會自動調用。

有人會問,對象內存被釋放時成員變量內存空間不是也被釋放瞭嗎

我們先看一段代碼

class MyClass
{
protected:
	int* p = new int;
public:
	MyClass(int i)
	{
		*p = i;
	}
};

這個MyClass類,類成員變量中在內存堆區開辟一個整型變量

堆區內存需要手動釋放,不然會造成內存泄漏,此時析構函數就派上用處瞭

以下為析構函數代碼實現:
~MyClass()
{
	delete p;
	p = NULL;
}

由於制作倉促,如有錯誤敬請指正

總結

本期簡單介紹OOP面向對象編程和構造函數,析構函數。

推薦閱讀: