国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

C++ ------類和對象詳解六大默認成員函數(shù)

這篇具有很好參考價值的文章主要介紹了C++ ------類和對象詳解六大默認成員函數(shù)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

類的6個默認成員函數(shù)

如果我們定義一個類,然后這個類中什么也沒有。那么這里的類就什么也沒有嗎?其實不然,任何類在里面什么都不寫時,編譯器都會生成6個默認成員函數(shù)。

概念

用戶沒有顯式實現(xiàn),編譯器會生成的成員函數(shù)稱為默認成員函數(shù)。
六個默認成員函數(shù)
C++ ------類和對象詳解六大默認成員函數(shù),C++,c++,開發(fā)語言

構(gòu)造函數(shù)

我們來看一個Date類

#include <iostream>
using namespace std;

class Date
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1;
	d1.Init(2023, 7, 23);
	d1.Print();
	Date d2;
	d2.Init(2023, 7, 24);
	d2.Print();
	return 0;
}

觀察上述代碼,我們需要顯式的調(diào)用Init函數(shù),這個函數(shù)可以給私有的成員變量賦值,但是如果每次都使用這個方法設(shè)置信息,就顯得有點麻煩了,這里我們引出了構(gòu)造函數(shù)的概念:

概念

構(gòu)造函數(shù)時特殊的成員函數(shù),名字與類名相同,創(chuàng)建類類型對象時由編譯器自動調(diào)用,以保證每個數(shù)據(jù)成員都有一個合適的初始值,并且在對象整個生命周期內(nèi)只調(diào)用一次。

特點

函數(shù)名和類名相同,沒有返回值,可以發(fā)生重載,對象實例化時編譯器自動調(diào)用構(gòu)造函數(shù)。除此之外我們還需要了解一下的特點,我們看一個代碼:

class Date
{
public:
	
	Date()
	{
		_year = 1;
		_month = 1;
		_day = 1;
	}
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	//實例化對象
	Date d;
	d.Print();
	return 0;
}

C++ ------類和對象詳解六大默認成員函數(shù),C++,c++,開發(fā)語言

我們看到上述代碼中我們顯式的定義了一個構(gòu)造函數(shù),編譯器會調(diào)用我們自己定義的構(gòu)造函數(shù),也就是說當我們自己定義了一個構(gòu)造函數(shù),編譯器就不會生成無參的默認構(gòu)造函數(shù)。
接下來我們了解一下默認構(gòu)造函數(shù):
我們再來看一段代碼

class Date
{
public:
	//構(gòu)造函數(shù) 任務初始化對象
	//無參構(gòu)造函數(shù)
	//編譯器會自動調(diào)用構(gòu)造函數(shù)。
	//需要注意,我們在顯式的定義構(gòu)造函數(shù)時,編譯器不會生成默認的構(gòu)造函數(shù)。
	//編譯器生成的默認構(gòu)造函數(shù)不會對內(nèi)置類型進行初始化,生成的構(gòu)造函數(shù)是
	//無參的構(gòu)造函數(shù)。
	//默認構(gòu)造函數(shù)包括一下三類:我們自己寫的無參構(gòu)造函數(shù),還有我們不寫時編譯器默認生成的無參構(gòu)造函數(shù)。
	//全缺省構(gòu)造函數(shù),這三個構(gòu)造函數(shù)只能在類中出現(xiàn)一個,否則就會出現(xiàn)調(diào)用的二義性。
	Date()
	{
		_year = 1;
		_month = 1;
		_day = 1;
	}
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	//實例化對象
	Date d;
	d.Print();
	return 0;
}

C++ ------類和對象詳解六大默認成員函數(shù),C++,c++,開發(fā)語言

我們可以看到,上述代碼發(fā)生了編譯錯誤,多個默認構(gòu)造函數(shù)和對重載函數(shù)的調(diào)用不明確。這是因為C++規(guī)定默認構(gòu)造函數(shù)分為編譯器自動生成的構(gòu)造函數(shù),自己定義的構(gòu)造函數(shù)和全缺省構(gòu)造函數(shù),這三個構(gòu)造函數(shù)只能在類中出現(xiàn)一個,所以我們在定義構(gòu)造函數(shù)時,不能將兩個默認構(gòu)造函數(shù)同時寫在同一個類中。
我們再來思考一個問題,編譯器自動生成的構(gòu)造函數(shù),會對內(nèi)置類型進行初始化嗎?答案是不會,我們通過以下代碼來驗證這一點

class Date
{
public:
	//需要注意,我們在顯式的定義構(gòu)造函數(shù)時,編譯器不會生成默認的構(gòu)造函數(shù)。
	//編譯器生成的默認構(gòu)造函數(shù)不會對內(nèi)置類型進行初始化,生成的構(gòu)造函數(shù)是
	//無參的構(gòu)造函數(shù)。
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	//實例化對象
	Date d;
	d.Print();
	return 0;
}

C++ ------類和對象詳解六大默認成員函數(shù),C++,c++,開發(fā)語言

我們可以看到運行結(jié)果中沒有對內(nèi)置類型初始化,那么默認生成的構(gòu)造函數(shù)會做些什么呢,C++把類型分為內(nèi)置類型和自定義類型,內(nèi)置類型就是語言提供的數(shù)據(jù)類型,如int,char等,自定義類型就是我們使用class/struct關(guān)鍵字自己定義的類型,編譯器默認生成的構(gòu)造函數(shù)會對自定義類型成員_t 調(diào)用它的默認構(gòu)造函數(shù)。

class Time
{
public:
	//自己定義的默認構(gòu)造函數(shù)
	Time()
	{
		cout << "Time()" << endl;
		_hour = 0;
		_minute = 0;
		_second = 0;
	}
private:
	int _hour;
	int _minute;
	int _second;
};

class Date
{
private:
	//基本類型
	int _year;
	int _month;
	int _day;
	//自定義類型
	Time _t;
};
int main()
{
	//實例化對象
	Date d;
	return 0;
}

C++ ------類和對象詳解六大默認成員函數(shù),C++,c++,開發(fā)語言
以上代碼是調(diào)用了Time的構(gòu)造函數(shù)的。那么對于內(nèi)置類型成員不初始化的缺陷,C++11又定義:內(nèi)置類型成員變量在類中聲明時可以給默認值。

class Time
{
public:
	//自己定義的默認構(gòu)造函數(shù)
	Time()
	{
		cout << "Time()" << endl;
		_hour = 0;
		_minute = 0;
		_second = 0;
	}
private:
	int _hour;
	int _minute;
	int _second;
};

class Date
{
public:
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	//基本類型
	//缺省值
	int _year = 1;
	int _month = 1;
	int _day = 1;
	//自定義類型
	Time _t;
};
int main()
{
	//實例化對象
	Date d;
	d.Print();
	return 0;
}

C++ ------類和對象詳解六大默認成員函數(shù),C++,c++,開發(fā)語言

析構(gòu)函數(shù)

我們來看下面的代碼:

typedef int DateType;
class Stack
{
public:
	//默認構(gòu)造函數(shù)
	Stack(size_t capacity = 3)
	{
		cout << "Stack(size_t capacity = 3)" << endl;
		_a = (DateType*)malloc(sizeof(DateType) * capacity);
		if (NULL == _a)
		{
			perror("malloc failed!");
			return;
		}
		_capacity = capacity;
		_top = 0;
	}

	void Push(DateType data)
	{
		//擴容
		_a[_top] = data;
		_top++;
	}
	//其他方法……

	void Destory()
	{
		free(_a);
		_a = NULL;
		_top = _capacity = 0;
	}
private:
	size_t _capacity;
	size_t _top;
	DateType* _a;
};

int main()
{
	Stack st;
	st.Push(1);
	st.Push(2);
	st.Push(3);
	st.Destory();
	return 0;
}

上面的代碼我們會發(fā)現(xiàn),在最后我們寫了一個函數(shù)叫做Destory,這里的這個函數(shù)的作用是銷毀資源,需要我們顯式調(diào)用,有點麻煩,那么我們怎么樣可以讓系統(tǒng)自動調(diào)用呢?我們就引出了析構(gòu)函數(shù)的概念。

概念

析構(gòu)函數(shù):析構(gòu)函數(shù)和構(gòu)造函數(shù)的功能相反,析構(gòu)函數(shù)不是完成對對象本身的銷毀,局部對象銷毀工作是由編譯器完成的。而對象在銷毀時會自動調(diào)用析構(gòu)函數(shù),完成對象中資源的清理工作。看以下代碼:

typedef int DateType;
class Stack
{
public:
	//默認構(gòu)造函數(shù)
	Stack(size_t capacity = 3)
	{
		cout << "Stack(size_t capacity = 3)" << endl;
		_a = (DateType*)malloc(sizeof(DateType) * capacity);
		if (NULL == _a)
		{
			perror("malloc failed!");
			return;
		}
		_capacity = capacity;
		_top = 0;
	}
	void Push(DateType data)
	{
		//擴容
		_a[_top] = data;
		_top++;
	}
	//其他方法……

	//析構(gòu)函數(shù)
	~Stack()
	{
		cout << "~Stack()" << endl;
		free(_a);
		_a = NULL;
		_top = _capacity = 0;
	}
	/*void Destory()
	{
		free(_a);
		_a = NULL;
		_top = _capacity = 0;
	}*/
private:
	size_t _capacity;
	size_t _top;
	DateType* _a;
};

int main()
{
	Stack st;
	st.Push(1);
	st.Push(2);
	st.Push(3);
	//st.Destory();
	return 0;
}

C++ ------類和對象詳解六大默認成員函數(shù),C++,c++,開發(fā)語言

我們可以看到上面的代碼調(diào)用了顯式定義的析構(gòu)函數(shù),析構(gòu)函數(shù)的特征是什么和構(gòu)造函數(shù)的特征相同嗎,我們來簡單討論一下:

特征

從上述代碼可知析構(gòu)函數(shù)具有如下特點:

  • 函數(shù)名和類名相同且在函數(shù)名的前面加上字符~。
  • 沒有返回值類型。
  • 一個類只能有一個析構(gòu)函數(shù)。若為顯示定義,系統(tǒng)會自動生成默認的析構(gòu)函數(shù),注意:析構(gòu)函數(shù)不能重載。
  • 對象聲明周期結(jié)束時,C++編譯系統(tǒng)自動調(diào)用析構(gòu)函數(shù)。編譯器默認生成的析構(gòu)函數(shù)不會free堆上的空間。
typedef int DateType;
class Stack
{
public:
	//默認構(gòu)造函數(shù)
	Stack(size_t capacity = 3)
	{
		cout << "Stack(size_t capacity = 3)" << endl;
		_a = (DateType*)malloc(sizeof(DateType) * capacity);
		if (NULL == _a)
		{
			perror("malloc failed!");
			return;
		}
		_capacity = capacity;
		_top = 0;
	}

	void Push(DateType data)
	{
		//擴容
		_a[_top] = data;
		_top++;
	}
	//其他方法……

	//析構(gòu)函數(shù)
	//~Stack()
	//{
	//	cout << "~Stack()" << endl;
	//	free(_a);
	//	_a = NULL;
	//	_top = _capacity = 0;
	//}
	/*void Destory()
	{
		free(_a);
		_a = NULL;
		_top = _capacity = 0;
	}*/
private:
	size_t _capacity;
	size_t _top;
	DateType* _a;
};

int main()
{
	Stack st;
	//st.Destory();
	return 0;
}

C++ ------類和對象詳解六大默認成員函數(shù),C++,c++,開發(fā)語言

  • 編譯器默認生成的析構(gòu)函數(shù),對自定義類型成員調(diào)用它們的析構(gòu)函數(shù)
class Time
{
public:
	~Time()
	{
		cout << "~Time()" << endl;
	}
private:
	int _hour;
	int _minute;
	int _second;
};
class Date
{
private:
	//基本類型
	int _year = 1970;
	int _month = 1;
	int _day = 1;

	//自定義類型
	Time _t;
};

int main()
{
	Date d;
	return 0;
}

C++ ------類和對象詳解六大默認成員函數(shù),C++,c++,開發(fā)語言

上面的程序運行結(jié)束后輸出 ~Time()
在main方法中根本沒有直接創(chuàng)建Time類的對象,為什么最后會調(diào)用Time類的析構(gòu)函數(shù)?
因為:main方法中創(chuàng)建了Date對象d,而d中包含4個成員變量,其中_year, _month,
_day三個是內(nèi)置類型成員,銷毀時不需要資源清理,最后系統(tǒng)直接將其內(nèi)存回收即可;而_t是Time類對象,所以在d銷毀時,要將其內(nèi)部包含的Time類的_t對象銷毀,所以要調(diào)用Time類的析構(gòu)函數(shù)。但是:main函數(shù)中不能直接調(diào)用Time類的析構(gòu)函數(shù),實際要釋放的是Date類對象,所以編譯器會調(diào)用Date類的析構(gòu)函數(shù),而Date沒有顯式提供,則編譯器會給Date類生成一個默認的析構(gòu)函數(shù),目的是在其內(nèi)部調(diào)用Time類的析構(gòu)函數(shù),即當Date對象銷毀時,要保證其內(nèi)部每個自定義對象都可以正確銷毀main函數(shù)中并沒有直接調(diào)用Time類析構(gòu)函數(shù),而是顯式調(diào)用編譯器為Date類生成的默認析構(gòu)函數(shù)。
注意:創(chuàng)建哪個類的對象則調(diào)用該類的析構(gòu)函數(shù),銷毀那個類的對象則調(diào)用該類的析構(gòu)函數(shù)。

  • 如果類中沒有申請資源時,析構(gòu)函數(shù)可以不寫,直接使用編譯器生成的默認析構(gòu)函數(shù),比如Date類;有資源申請時,一定要寫,否則會造成資源泄漏,比如Stack類。

拷貝構(gòu)造函數(shù)

我們來看下面的代碼引出拷貝構(gòu)造函數(shù)

class Date
{
public:
	//全缺省默認構(gòu)造
	Date(int year = 2023, int month = 7, int day = 30)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
private:
	//基本類型
	int _year = 1970;
	int _month = 1;
	int _day = 1;
};

int main()
{
	Date d;
	//我們?nèi)绾斡靡汛嬖诘膶ο髞順?gòu)造一個和它相同的對象呢?顯然,
	//我們使用拷貝構(gòu)造可以完成這個任務。
	//調(diào)用拷貝構(gòu)造
	Date d1(d);
	return 0;
}

上述代碼我們知道想要利用已存在的對象,實例化一個和它相同的對象我們需要調(diào)用拷貝構(gòu)造函數(shù)。

概念

拷貝構(gòu)造函數(shù):只有單個形參,該形參是對類類型對象的應用一般常用const修飾,目的是為了不能對原有的對象進行修改,在用已存在的類類型對象創(chuàng)建新對象時由編譯器自動調(diào)用。

特點

  • 拷貝構(gòu)造函數(shù)時構(gòu)造函數(shù)的一個重載形式。
  • 拷貝構(gòu)造函數(shù)的參數(shù)只有一個且必須是類類型對象的引用,使用傳值方式編譯器直接報錯,因為會引發(fā)無窮遞歸調(diào)用拷貝構(gòu)造。我們來看下面的代碼;
class Date
{
public:
	//全缺省默認構(gòu)造
	Date(int year = 2023, int month = 7, int day = 30)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date(Date d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
private:
	//基本類型
	int _year = 1970;
	int _month = 1;
	int _day = 1;
};

int main()
{
	Date d;
	//我們?nèi)绾斡靡汛嬖诘膶ο髞順?gòu)造一個和它相同的對象呢?顯然,
	//我們使用拷貝構(gòu)造可以完成這個任務。
	//調(diào)用拷貝構(gòu)造
	Date d1(d);
	return 0;
}

C++ ------類和對象詳解六大默認成員函數(shù),C++,c++,開發(fā)語言

上面的拷貝構(gòu)造函數(shù)參數(shù)為傳值調(diào)用,這會引發(fā)編譯器報錯,這是因為在傳值傳參時會進行拷貝構(gòu)造,而調(diào)用拷貝構(gòu)造還是需要傳參,這就會導致函數(shù)一直傳參,傳值傳參就會拷貝構(gòu)造。那么就造成了無窮遞歸調(diào)用

C++ ------類和對象詳解六大默認成員函數(shù),C++,c++,開發(fā)語言

  • 若為顯式定義,編譯器會自動生成默認的拷貝構(gòu)造函數(shù),默認的拷貝構(gòu)造函數(shù)對象按內(nèi)存存儲按字節(jié)序完成拷貝,這種拷貝叫做淺拷貝或者值拷貝,但是我們在拷貝堆上的數(shù)據(jù)時需要把堆上的數(shù)據(jù)也拷貝過來,而不單單是拷貝一個堆上空間的一個指針。這不是真正的拷貝,也算是淺拷貝,上面的這種拷貝叫做深拷貝,這里的深拷貝會在以后詳細講解。我們這里只關(guān)心淺拷貝。
class Date
{
public:
	//全缺省默認構(gòu)造
	Date(int year = 2023, int month = 7, int day = 30)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	//基本類型
	int _year = 1970;
	int _month = 1;
	int _day = 1;
};

int main()
{
	Date d;
	//我們?nèi)绾斡靡汛嬖诘膶ο髞順?gòu)造一個和它相同的對象呢?顯然,
	//我們使用拷貝構(gòu)造可以完成這個任務。
	//調(diào)用拷貝構(gòu)造,我們沒有顯式定義拷貝構(gòu)造函數(shù),編譯器會默認生成拷貝構(gòu)造。
	Date d1(d);
	return 0;
}

這里還是一樣,對于自定義類型,編譯器默認生成的拷貝構(gòu)造函數(shù)會去調(diào)用自定義類型的拷貝構(gòu)造函數(shù)和普通的構(gòu)造函數(shù)相同。

  • 編譯器生成的默認拷貝構(gòu)造函數(shù)已經(jīng)可以完成字節(jié)序的值拷貝了,我們對于沒有涉及到資源申請的類,拷貝構(gòu)造函數(shù)是否寫都可以;一旦涉及到資源申請時,則拷貝構(gòu)造函數(shù)是一定要寫的,否則就是淺拷貝,我們需要深拷貝。
    我們來看下面的代碼:
typedef int DataType;
class Stack
{
public:
	//全缺省默認構(gòu)造函數(shù)
	Stack(size_t capacity = 10)
	{
		_a = (DataType*)malloc(capacity * sizeof(int));
		if (NULL == _a)
		{
			perror("malloc failed!");
			return;
		}

		_capacity = capacity;
		_top = 0;
	}

	void Push(const DataType x)
	{
		//擴容
		_a[_top] = x;
		_top++;
	}
	//析構(gòu)函數(shù)
	~Stack()
	{
		if (_a)
		{
			free(_a);
			_a = NULL;
			_capacity = _top = 0;
		}
	}
private:
	DataType* _a;
	size_t _top;
	size_t _capacity;
};

int main()
{
	Stack s1;
	s1.Push(1);
	s1.Push(2);
	s1.Push(3);
	s1.Push(4);

	Stack s2(s1);
	return 0;
}

C++ ------類和對象詳解六大默認成員函數(shù),C++,c++,開發(fā)語言

該段程序運行崩潰,因為上述程序?qū)嵗艘粋€對象s1,入棧4個數(shù)據(jù)。然后再使用該對象來拷貝構(gòu)造一個新的對象,當程序結(jié)束時,s2會調(diào)用析構(gòu)函數(shù)對資源進行銷毀,而s1也會調(diào)用析構(gòu)函數(shù)對資源進行銷毀,那么這就出現(xiàn)了free兩次的情況,解決方案只能是進行深度拷貝,這里的深度拷貝會在以后的文章中講解
C++ ------類和對象詳解六大默認成員函數(shù),C++,c++,開發(fā)語言

  • 拷貝構(gòu)造的應用場景
    使用已存在對象創(chuàng)建新對象,上面的代碼就是這種場景
    函數(shù)參數(shù)類型為類類型
    函數(shù)返回值類型為類類型對象
    看一下下面的代碼
class Date
{
public:
	//不是默認構(gòu)造函數(shù)
	Date(int year, int minute, int day)
	{
		cout << "Date(int year, int minute, int day)" << this << endl;
	}
	//拷貝構(gòu)造
	Date(const Date& d)
	{
		cout << "Date(const Date& d)" << endl;
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	//析構(gòu)函數(shù)
	~Date()
	{
		cout << "~Date()" << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

Date Test(Date d)
{
	Date temp(d);
	return temp;
}

int main()
{
	//調(diào)用構(gòu)造函數(shù)
	Date d1(2023, 7, 30);
	Test(d1);
	return 0;
}

C++ ------類和對象詳解六大默認成員函數(shù),C++,c++,開發(fā)語言

上面的代碼在構(gòu)造d1對象時使用了構(gòu)造函數(shù),在給類類型形參傳參的時候調(diào)用了一次拷貝構(gòu)造,在用d構(gòu)造temp對象時使用了一次拷貝構(gòu)造,在返回temp對象時調(diào)用了一次拷貝構(gòu)造,程序運行結(jié)束后銷毀Test中的temp對象使用了一次析構(gòu)函數(shù),銷毀Test函數(shù)的參數(shù)d使用了析構(gòu)函數(shù),銷毀Test函數(shù)返回時創(chuàng)建的臨時對象使用了一次析構(gòu)函數(shù),銷毀main函數(shù)中的d1使用了一次析構(gòu)函數(shù)。為了提高效率我們在做類類型傳參和類類型作為返回值的時候,盡量使用引用。

賦值運算符重載

在這一節(jié)我們需要先了解運算符重載的概念和實現(xiàn)

運算符重載的概念

C++為了增強代碼的可讀性引入了運算符重載,運算符重載是具有特殊函數(shù)名的函數(shù),也具有其返回類型,函數(shù)名字以及參數(shù)列表,其返回值類型和參數(shù)列表與普通的函數(shù)類似,下面是一個運算符重載的例子:

class Date
{
public:
	//不是默認構(gòu)造函數(shù)
	Date(int year, int minute, int day)
	{
		cout << "Date(int year, int minute, int day)" << this << endl;
	}
	//拷貝構(gòu)造
	Date(const Date& d)
	{
		cout << "Date(const Date& d)" << endl;
	}
	//析構(gòu)函數(shù)
	~Date()
	{
		cout << "~Date()" << endl;
	}
public:
	int _year;
	int _month;
	int _day;
};

//恒等運算符重載
bool operator==(const Date& d1, const Date& d2)
{
	//這里訪問不了的類的私有成員,我們需要把類的私有成員變成公有的,但是這就不符合我們的封裝思想了
	//因為我們這里只是講解運算符的重載就先不要管這個東西了,下面我們會介紹怎么樣才能避免這種情況
	return d1._year == d2._year && d1._month == d2._month && d1._day == d2._day;
}

int main()
{
	Date d1(2023,7,30);
	Date d2(2023,7,30);
	//可以隱式調(diào)用也可以顯式調(diào)用
	cout << (d1 == d2) << endl;
	//顯式調(diào)用
	cout << operator==(d1, d2) << endl;
}

C++ ------類和對象詳解六大默認成員函數(shù),C++,c++,開發(fā)語言

為了解決上述問題,我們需要把運算符重載函數(shù),寫到類里面去,但是函數(shù)參數(shù)會少一個,這是由于成為成員函數(shù)就會增加一個this指針,而運算符重載函數(shù)的參數(shù)有幾個是由操作符的操作數(shù)決定的。也可以用友元函數(shù)進行解決,這個我們后面會說。

class Date
{
public:
	//不是默認構(gòu)造函數(shù)
	Date(int year, int minute, int day)
	{
		cout << "Date(int year, int minute, int day)" << this << endl;
	}
	//拷貝構(gòu)造
	Date(const Date& d)
	{
		cout << "Date(const Date& d)" << endl;
	}
	//析構(gòu)函數(shù)
	~Date()
	{
		cout << "~Date()" << endl;
	}
	//運算符重載
	bool operator==(const Date& d1)
	{
		return (*this)._year == d1._year && (*this)._month == d1._month && (*this)._day == d1._day;
	}
public:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2023,7,30);
	Date d2(2023,7,30);
	//可以隱式調(diào)用也可以顯式調(diào)用
	cout << (d1 == d2) << endl;
	//顯式調(diào)用
	cout <<d1.operator==(d2) << endl;
}

C++ ------類和對象詳解六大默認成員函數(shù),C++,c++,開發(fā)語言

特性

  • 不能通過連接其他符號來創(chuàng)建新的操作符:比如operator@
  • 重載操作符必須有一個類類型參數(shù)
  • 用于內(nèi)置類型的運算符,其含義不能改變,例如:內(nèi)置類型的+,不能改變其含義。
  • 作為類成員函數(shù)重載時,其形參看起來比操作數(shù)數(shù)目少1,因為成員函數(shù)的第一個參數(shù)為隱藏的this。
  • .* :: sizeof ?: . 不能被重載。

賦值運算符重載

class Date
{
public:
	//不是默認構(gòu)造函數(shù)
	Date(int year, int minute, int day)
	{
		cout << "Date(int year, int minute, int day)" << this << endl;
	}
	//拷貝構(gòu)造
	Date(const Date& d)
	{
		cout << "Date(const Date& d)" << endl;
	}
	//析構(gòu)函數(shù)
	~Date()
	{
		cout << "~Date()" << endl;
	}
	//運算符重載
	bool operator==(const Date& d1)
	{
		return _year == d1._year && 
			_month == d1._month && 
			_day == d1._day;
	}
	//賦值運算符重載
	//賦值運算符不能在類外定義,因為我們沒有在類中顯式定義賦值運算符重載函數(shù)
	//編譯器會自動生成,這就和類外定義的賦值運算符重載函數(shù)沖突了。另外定義成全局函數(shù)
	//就沒有this指針這一說法了,就必須寫兩個參數(shù)
	Date& operator=(const Date& d1)
	{
		//我們需要確定不是兩個相同的對象賦值
		if (this != &d1)
		{
			cout << "Date& operator=(const Date& d1)" << endl;
			_year = d1._year;
			_month = d1._month;
			_day = d1._day;
		}
		return *this;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	//Date d1(2023, 7, 30);
	//Date d2(2023, 7, 30);
	可以隱式調(diào)用也可以顯式調(diào)用
	//cout << (d1 == d2) << endl;
	顯式調(diào)用
	//cout << d1.operator==(d2) << endl;

	//兩個對象賦值操作就要用到賦值運算符重載
	Date d3(1,1,1);
	Date d4(1,1,1);
	d3 = d4;

	//注意寫成這樣為調(diào)用拷貝構(gòu)造
	Date d5 = d3;
}

C++ ------類和對象詳解六大默認成員函數(shù),C++,c++,開發(fā)語言

格式

  • 賦值運算符重載格式
  • 參數(shù)類型:const T&,傳遞引用可以提高傳參效率
  • 返回值類型:T&: 返回引用可以提高返回的效率,有返回值目的是為了支持連續(xù)賦值
  • 檢測是否自己給自己賦值
  • 返回* this:要符合連續(xù)賦值的含義。 a = b = c

特性

賦值運算符只能重載成類的成員函數(shù)不能重載成全局函數(shù),因為賦值運算符重載函數(shù)是一個默認成員函數(shù),所以編譯器會默認生成賦值重載函數(shù),跟構(gòu)造函數(shù)和拷貝函數(shù)的行為一樣。Date和MyQueue不需要我們自己實現(xiàn)賦值重載,stack需要我們自己實現(xiàn),因為默認生成的是淺拷貝。

class Date
{
	friend Date& operator=(const Date& d1, const Date& d2);
public:
	//不是默認構(gòu)造函數(shù)
	Date(int year, int minute, int day)
	{
		cout << "Date(int year, int minute, int day)" << this << endl;
	}
	//拷貝構(gòu)造
	Date(const Date& d)
	{
		cout << "Date(const Date& d)" << endl;
	}
	//析構(gòu)函數(shù)
	~Date()
	{
		cout << "~Date()" << endl;
	}
	//運算符重載
	bool operator==(const Date& d1)
	{
		return _year == d1._year &&
			_month == d1._month &&
			_day == d1._day;
	}
	//賦值運算符重載
	//賦值運算符不能在類外定義,因為我們沒有在類中顯式定義賦值運算符重載函數(shù)
	//編譯器會自動生成,這就和類外定義的賦值運算符重載函數(shù)沖突了。另外定義成全局函數(shù)
	//就沒有this指針這一說法了,就必須寫兩個參數(shù)

private:
	int _year;
	int _month;
	int _day;
};

Date& operator=(const Date& d1,const Date& d2)
{
	//我們需要確定不是兩個相同的對象賦值
	if (&d2 != &d1)
	{
		cout << "Date& operator=(const Date& d1)" << endl;
		d1._year = d2._year;
		d1._month = d2._month;
		d1._day = d2._day;
	}
	return d1;
}
int main()
{
	//Date d1(2023, 7, 30);
	//Date d2(2023, 7, 30);
	可以隱式調(diào)用也可以顯式調(diào)用
	//cout << (d1 == d2) << endl;
	顯式調(diào)用
	//cout << d1.operator==(d2) << endl;

	//兩個對象賦值操作就要用到賦值運算符重載
	Date d3(1, 1, 1);
	Date d4(1, 1, 1);
	d3 = d4;

	//注意寫成這樣為調(diào)用拷貝構(gòu)造
	Date d5 = d3;
}

C++ ------類和對象詳解六大默認成員函數(shù),C++,c++,開發(fā)語言

C++ primer中有一句話說:我們可以重載賦值運算符。不論形參的類型是什么,賦值運算符都必須定義為成員函數(shù)。

用戶沒有顯式實現(xiàn)時,編譯器會生成一個默認賦值運算符重載,以值得方式逐字節(jié)拷貝。注意:內(nèi)置類型成員變量是直接賦值的,而自定義類型成員變量需要調(diào)用對應類的賦值運算符重載完成賦值。

class Time
{
public:
	//構(gòu)造函數(shù)
	Time(int hour = 0, int minute = 0, int second = 0)
	{
		cout << "Date(int hour = 0, int minute = 0, int second = 0)" << endl;
	}

	Time& operator=(const Time& t)
	{
		//判斷是不是同一個對象
		if (this != &t)
		{
			cout << "Time& operator=(const Time& t)" << endl;
			_hour = t._hour;
			_minute = t._minute;
			_second = t._second;
		}
		return *this;
	}
private:
	int _hour;
	int _minute;
	int _second;
};
class Date
{
public:
	//不是默認構(gòu)造函數(shù)
	Date(int year, int month, int day)
	{
		cout << "Date(int year, int month, int day)" << this << endl;
	}
	//拷貝構(gòu)造
	Date(const Date& d)
	{
		cout << "Date(const Date& d)" << endl;
	}
	//析構(gòu)函數(shù)
	~Date()
	{
		cout << "~Date()" << endl;
	}
	
private:
	//內(nèi)置類型
	int _year;
	int _month;
	int _day;
	//自定義類型
	Time _t;
};


int main()
{
	Date d3(1, 1, 1);
	Date d4(1, 1, 1);
	d3 = d4;

	//注意寫成這樣為調(diào)用拷貝構(gòu)造
	Date d5 = d3;
}

C++ ------類和對象詳解六大默認成員函數(shù),C++,c++,開發(fā)語言

如果類中未涉及到資源管理,賦值運算符的重載是否實現(xiàn)都可以,一旦涉及到資源管理則必須要顯式實現(xiàn)。

取地址及const取地址操作符重載

這里就不做太多的介紹,這兩個運算符一般不需要重載,使用編譯器生成的默認取地址的重載即可,只有特殊情況,才需要重載,比如想讓別人獲取到指定的內(nèi)容。

class Date
{
public:
	Date* operator&()
	{
		return this;
	}
	const Date* operator&()const //這里的const代表了不能修改對象
	{
		return this;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
	cout << &d1 << endl;
	Date* p1 = &d1;
	cout << p1 << endl;
}

C++ ------類和對象詳解六大默認成員函數(shù),C++,c++,開發(fā)語言文章來源地址http://www.zghlxwxcb.cn/news/detail-618709.html

到了這里,關(guān)于C++ ------類和對象詳解六大默認成員函數(shù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務器費用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包