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

【C++】類和對象(中)之拷貝構(gòu)造與運(yùn)算符、操作符重載

這篇具有很好參考價(jià)值的文章主要介紹了【C++】類和對象(中)之拷貝構(gòu)造與運(yùn)算符、操作符重載。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

【C++】類和對象(中)之拷貝構(gòu)造與運(yùn)算符、操作符重載,C++,c++,開發(fā)語言

??樊梓慕:個(gè)人主頁

???個(gè)人專欄:《C語言》《數(shù)據(jù)結(jié)構(gòu)》《藍(lán)橋杯試題》《LeetCode刷題筆記》《實(shí)訓(xùn)項(xiàng)目》《C++》

??每一個(gè)不曾起舞的日子,都是對生命的辜負(fù)


前言

我們繼續(xù)學(xué)習(xí)默認(rèn)成員函數(shù),本篇文章博主帶來的是拷貝構(gòu)造函數(shù)與運(yùn)算符、操作符重載的講解,并且還有const成員所帶來的一系列問題,最后博主會(huì)給大家貼出利用前面所學(xué)知識寫出的日期類。


歡迎大家??收藏??以便未來做題時(shí)可以快速找到思路,巧妙的方法可以事半功倍。

=========================================================================

GITEE相關(guān)代碼:??fanfei_c的倉庫??

=========================================================================


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

1.1概念

在介紹拷貝構(gòu)造函數(shù)之前,我想先舉一個(gè)例子來告訴大家為什么會(huì)有拷貝構(gòu)造?

比如:

class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
	Date d2(d1);//這里是什么行為?
	return 0;
}

請觀察我在代碼中標(biāo)識的部分,很明顯這里是將d1作為實(shí)參傳遞給構(gòu)造函數(shù)。

我們之前學(xué)習(xí)函數(shù)時(shí),曾說過,形參是實(shí)參的一份臨時(shí)拷貝。

那么好了,這就是拷貝構(gòu)造函數(shù)存在的其中一個(gè)意義。


拷貝構(gòu)造函數(shù):只有單個(gè)形參,該形參是對本類類型對象的引用(一般常用const修飾),在用已存在的類類型對象創(chuàng)建新對象時(shí)由編譯器自動(dòng)調(diào)用。


1.2特征

拷貝構(gòu)造函數(shù)也是特殊的成員函數(shù),其特征如下:

1.拷貝構(gòu)造函數(shù)是構(gòu)造函數(shù)的一個(gè)重載形式。

2.拷貝構(gòu)造函數(shù)的參數(shù)只有一個(gè)且必須是類類型對象的引用,使用傳值方式編譯器直接報(bào)錯(cuò),因?yàn)闀?huì)引發(fā)?無窮遞歸調(diào)用?。


??為什么這里會(huì)引發(fā)無窮遞歸調(diào)用??


前面對于拷貝構(gòu)造函數(shù)的定義是這樣說的:拷貝構(gòu)造函數(shù)在用已存在的類類型對象創(chuàng)建新對象時(shí)由編譯器自動(dòng)調(diào)用。

我們觀察下面的代碼:

Date(const Date date)//你會(huì)發(fā)現(xiàn)這里報(bào)錯(cuò)了??
{
	_year = date._year;
	_month = date._month;
	_day = date._day;
int main()
{
    Date d1;
    Date d2(d1);
}

?當(dāng)d1作為參數(shù)傳遞給拷貝構(gòu)造函數(shù)時(shí),是不是會(huì)再次調(diào)用拷貝構(gòu)造函數(shù)??

那我們就找到為什么會(huì)引發(fā)無窮遞歸調(diào)用的答案了。

【C++】類和對象(中)之拷貝構(gòu)造與運(yùn)算符、操作符重載,C++,c++,開發(fā)語言


解決的方案就是特征所描述的那樣:拷貝構(gòu)造函數(shù)的參數(shù)只有一個(gè)且必須是類類型對象的引用。?

也就是這樣:

Date(const Date& d)
{
    _year = d._year;
    _month = d._month;
    _day = d._day;
}

3.若未顯式定義,編譯器會(huì)生成默認(rèn)的拷貝構(gòu)造函數(shù)。 默認(rèn)的拷貝構(gòu)造函數(shù)對象按內(nèi)存存儲(chǔ)按字節(jié)序完成拷貝,這種拷貝叫做淺拷貝,或者值拷貝。


4.編譯器生成的默認(rèn)拷貝構(gòu)造函數(shù)(淺拷貝)已經(jīng)可以完成字節(jié)序的值拷貝了,還需要自己顯式實(shí)現(xiàn)嗎?當(dāng)然像日期類這樣的類是沒必要的。那么下面的類呢?驗(yàn)證一下試試?

typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 10)
	{
		_array = (DataType*)malloc(capacity * sizeof(DataType));
		if (nullptr == _array)
		{
			perror("malloc申請空間失敗");
			return;
		}
		_size = 0;
		_capacity = capacity;
	}
	void Push(const DataType& data)
	{
		// CheckCapacity();
		_array[_size] = data;
		_size++;
	}
	~Stack()
	{
		if (_array)
		{
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	DataType* _array;
	size_t _size;
	size_t _capacity;
};

int main()
{
	Stack s1;
	s1.Push(1);
	s1.Push(2);
	s1.Push(3);
	s1.Push(4);
	Stack s2(s1);
	return 0;
}

程序報(bào)錯(cuò):

【C++】類和對象(中)之拷貝構(gòu)造與運(yùn)算符、操作符重載,C++,c++,開發(fā)語言


??那么對于日期類,他所做的拷貝就是淺拷貝,那淺拷貝會(huì)不會(huì)有風(fēng)險(xiǎn)存在呢??


對于日期類,淺拷貝沒有風(fēng)險(xiǎn)。

但是對于自己開了空間的自定義類型來講,淺拷貝可能會(huì)引發(fā)大麻煩。

?大家還記得之前學(xué)習(xí)的析構(gòu)函數(shù)么,通過前面的學(xué)習(xí)我們知道,析構(gòu)函數(shù)會(huì)在對象銷毀時(shí)時(shí)自動(dòng)調(diào)用。

那么如果對于自己開了空間的自定義類型來講,單純的進(jìn)行淺拷貝,就會(huì)有兩個(gè)對象的兩個(gè)指針指向相同的空間,那這兩個(gè)對象在銷毀時(shí),自動(dòng)調(diào)用析構(gòu)函數(shù),就會(huì)發(fā)生同一塊空間釋放兩次的情況,顯然程序會(huì)崩潰。

【C++】類和對象(中)之拷貝構(gòu)造與運(yùn)算符、操作符重載,C++,c++,開發(fā)語言


?那如何避免這樣的問題呢,很顯然我們需要像構(gòu)造函數(shù)那樣,自己設(shè)計(jì)一個(gè)函數(shù)用來進(jìn)行拷貝,這樣的拷貝被稱為深拷貝

一般比如順序表、鏈表、二叉樹等開了空間的自定義類型都需要深拷貝。


那么我們可以得到結(jié)論:

  1. 內(nèi)置類型成員完成值拷貝;
  2. 自定義類型調(diào)用該成員的拷貝構(gòu)造。

那么都有什么樣的場景用到了拷貝構(gòu)造呢?

當(dāng)用一個(gè)已初始化過了的自定義類類型對象去初始化另一個(gè)新構(gòu)造的對象的時(shí)候,拷貝構(gòu)造函數(shù)就會(huì)被自動(dòng)調(diào)用。也就是說,當(dāng)類的對象需要拷貝時(shí),拷貝構(gòu)造函數(shù)將會(huì)被調(diào)用。

以下情況都會(huì)調(diào)用拷貝構(gòu)造函數(shù):

① 程序中需要新建立一個(gè)對象,并用另一個(gè)同類的對象對它初始化,如前面介紹的那樣。

② 當(dāng)函數(shù)的參數(shù)為類的對象時(shí)。在調(diào)用函數(shù)時(shí)需要將實(shí)參對象完整地傳遞給形參,也就是需要建立一個(gè)實(shí)參的拷貝,這就是按實(shí)參復(fù)制一個(gè)形參,系統(tǒng)是通過調(diào)用復(fù)制構(gòu)造函數(shù)來實(shí)現(xiàn)的,這樣能保證形參具有和實(shí)參完全相同的值。

③ 函數(shù)的返回值是類的對象。在函數(shù)調(diào)用完畢將返回值帶回函數(shù)調(diào)用處時(shí)。此時(shí)需要將函數(shù)中的對象復(fù)制一個(gè)臨時(shí)對象并傳給該函數(shù)的調(diào)用處。?


1.3補(bǔ)充的一些知識

首先再來給大家強(qiáng)化一下構(gòu)造和拷貝構(gòu)造的理解。

觀察下面的代碼:

int main()
{
	A aa1(1);    //構(gòu)造

	// 一個(gè)已經(jīng)存在的對象拷貝初始化另一個(gè)要?jiǎng)?chuàng)建的對象,就是拷貝構(gòu)造

	A aa2(aa1);  // 拷貝構(gòu)造
	A aa3 = aa1; // 拷貝構(gòu)造 or 賦值拷貝 -> 拷貝構(gòu)造

	// 兩個(gè)已經(jīng)存在的對象拷貝是賦值拷貝
	aa2 = aa3;

	return 0;
}

?本質(zhì)上講,A aa2(aa1)和A aa2=aa1兩種寫法是一樣的,都屬于拷貝構(gòu)造。

?博主還會(huì)在接下來的文章中,介紹更多有關(guān)構(gòu)造和拷貝構(gòu)造的內(nèi)容,這里的內(nèi)容比較瑣碎,目前的知識支撐還不夠,所以我們還要往后學(xué)幾章。


2.運(yùn)算符重載

2.1運(yùn)算符重載

C++為了增強(qiáng)代碼的可讀性引入了運(yùn)算符重載,運(yùn)算符重載是具有特殊函數(shù)名的函數(shù),也具有其返回值類型,函數(shù)名字以及參數(shù)列表,其返回值類型與參數(shù)列表與普通的函數(shù)類似。

函數(shù)名字為:關(guān)鍵字operator后面接需要重載的運(yùn)算符符號。
函數(shù)原型:返回值類型 operator操作符(參數(shù)列表)

注意:

  • 不能通過連接其他符號來創(chuàng)建新的操作符:比如operator@。
  • 重載操作符必須有一個(gè)類類型參數(shù)。
  • 用于內(nèi)置類型的運(yùn)算符,其含義不能改變,例如:內(nèi)置的整型+,不能改變其含義。
  • 作為類成員函數(shù)重載時(shí),其形參看起來比操作數(shù)數(shù)目少1,因?yàn)槌蓡T函數(shù)的第一個(gè)參數(shù)為隱藏的this。
  • .*? ::? sizeof? ?:(三目操作符)? .? 注意以上5個(gè)運(yùn)算符不能重載。這個(gè)經(jīng)常在筆試選擇題中出現(xiàn)。

我們來實(shí)現(xiàn)一個(gè)運(yùn)算符==的重載試試看:

大家同時(shí)思考一個(gè)問題:運(yùn)算符重載函數(shù)是放在類內(nèi)部,還是全局呢?

class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//private:    這里是為了示例,一般成員變量為私有
	int _year;
	int _month;
	int _day;
};
// 這里會(huì)發(fā)現(xiàn)運(yùn)算符重載成全局的就需要成員變量是公有的,那么問題來了,封裝性如何保證?
bool operator==(const Date& d1, const Date& d2)
{
	return d1._year == d2._year
		&& d1._month == d2._month
		&& d1._day == d2._day;
}
void Test()
{
	Date d1(2018, 9, 26);
	Date d2(2018, 9, 27);
	cout << (d1 == d2) << endl;
}

我們發(fā)現(xiàn)如果運(yùn)算符重載成全局的,一般來講類的成員變量都是私有的,那么如何訪問成員變量進(jìn)行運(yùn)算呢?

這里其實(shí)可以用我們后面學(xué)習(xí)的友元解決,或者干脆重載成成員函數(shù)。

由于友元我們還沒講,那就先試試看將運(yùn)算符重載函數(shù)放到類內(nèi)部。

class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	// bool operator==(Date* this, const Date& d2)
	// 這里需要注意的是,左操作數(shù)是this,指向調(diào)用函數(shù)的對象
	bool operator==(const Date& d2)
	{
		return _year == d2._year
		    && _month == d2._month
			&& _day == d2._day;
	}
private:
	int _year;
	int _month;
	int _day;
};

還記得我們前面學(xué)習(xí)的this指針是隱藏的參數(shù)吧。

我們知道==運(yùn)算符需要兩個(gè)操作數(shù),所以運(yùn)算符重載函數(shù)只需要一個(gè)顯式參數(shù),另一個(gè)為隱藏參數(shù)*this。?


2.2賦值運(yùn)算符重載

1. 賦值運(yùn)算符重載格式

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

class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	Date& operator=(const Date& d)
	{
		if (this != &d)//檢測是否自己給自己賦值
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}
private:
	int _year;
	int _month;
	int _day;
};

2.賦值運(yùn)算符只能重載成類的成員函數(shù)不能重載成全局函數(shù)(和普通運(yùn)算符的區(qū)別)

class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	int _year;
	int _month;
	int _day;
};
// 賦值運(yùn)算符重載成全局函數(shù),注意重載成全局函數(shù)時(shí)沒有this指針了,需要給兩個(gè)參數(shù)
Date& operator=(Date& left, const Date& right)
{
	if (&left != &right)
	{
		left._year = right._year;
		left._month = right._month;
		left._day = right._day;
	}
	return left;
}
// 編譯失?。?// error C2801: “operator =”必須是非靜態(tài)成員

原因:賦值運(yùn)算符如果不顯式實(shí)現(xiàn),編譯器會(huì)生成一個(gè)默認(rèn)的。此時(shí)用戶再在類外自己實(shí)現(xiàn)一個(gè)全局的賦值運(yùn)算符重載,就和編譯器在類中生成的默認(rèn)賦值運(yùn)算符重載沖突了,故賦值運(yùn)算符重載只能是類的成員函數(shù)。


3.用戶沒有顯式實(shí)現(xiàn)時(shí),編譯器會(huì)生成一個(gè)默認(rèn)賦值運(yùn)算符重載,以值的方式逐字節(jié)拷貝(淺拷貝)。

注意:內(nèi)置類型成員變量是直接賦值的,而自定義類型成員變量需要調(diào)用對應(yīng)類的賦值運(yùn)算符重載完成賦值。

class Time
{
public:
	Time()
	{
		_hour = 1;
		_minute = 1;
		_second = 1;
	}
	Time& operator=(const Time& t)
	{
		if (this != &t)
		{
			_hour = t._hour;
			_minute = t._minute;
			_second = t._second;
		}
		return *this;
	}
private:
	int _hour;
	int _minute;
	int _second;
};
class Date
{
private:
	// 基本類型(內(nèi)置類型)
	int _year = 1970;
	int _month = 1;
	int _day = 1;
	// 自定義類型
	Time _t;
};
int main()
{
	Date d1;
	Date d2;
	d1 = d2;//重載賦值運(yùn)算符
	return 0;
}

有沒有發(fā)現(xiàn)這里和構(gòu)造函數(shù)仍然十分相似。

內(nèi)置類型執(zhí)行淺拷貝,自定義類型調(diào)用自己的重載賦值運(yùn)算符。?

為什么自定義類型不能簡單的進(jìn)行淺拷貝,而還要自己設(shè)計(jì)深拷貝?

相信前面講解的拷貝函數(shù)的二次析構(gòu)問題已經(jīng)給了你答案,?我們再在這里舉一個(gè)例子加深大家的印象。

// 這里會(huì)發(fā)現(xiàn)下面的程序會(huì)崩潰掉?這里就需要我們以后講的深拷貝去解決。
typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 10)
	{
		_array = (DataType*)malloc(capacity * sizeof(DataType));
		if (nullptr == _array)
		{
			perror("malloc申請空間失敗");
			return;
		}
		_size = 0;
		_capacity = capacity;
	}
	void Push(const DataType& data)
	{
		// CheckCapacity();
		_array[_size] = data;
		_size++;
	}
	~Stack()
	{
		if (_array)
		{
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	DataType* _array;
	size_t _size;
	size_t _capacity;
};
int main()
{
	Stack s1;
	s1.Push(1);
	s1.Push(2);
	s1.Push(3);
	s1.Push(4);
	Stack s2;
	s2 = s1;//這里是默認(rèn)的賦值運(yùn)算符,完成的是淺拷貝
	return 0;
}

如果前面的二次析構(gòu)你理解了的話,這里不是問題。

分析:

【C++】類和對象(中)之拷貝構(gòu)造與運(yùn)算符、操作符重載,C++,c++,開發(fā)語言

總結(jié)一下:

  • 如果類中未涉及到資源管理,賦值運(yùn)算符是否實(shí)現(xiàn)都可以;
  • 一旦涉及到資源管理則必須要實(shí)現(xiàn)。

2.3流運(yùn)算符重載

流運(yùn)算符設(shè)計(jì)的初衷是為了解決自定義類型的輸入和輸出問題。

那么就一定會(huì)涉及到流運(yùn)算符重載的相關(guān)內(nèi)容。

但是流運(yùn)算符又不能和其他運(yùn)算符一樣重載到類內(nèi)部,相反,流運(yùn)算符必須實(shí)現(xiàn)到全局,這是為什么呢?

我們知道成員函數(shù)有一個(gè)隱藏的參數(shù)this,流運(yùn)算符也是一個(gè)雙目操作符,一般流運(yùn)算符我們寫為cout<<a;

但假設(shè)我們將流運(yùn)算符重載到類內(nèi)部作成員函數(shù)的話,第一個(gè)參數(shù)為this,所以好像我們這樣寫才是對的a<<cout;

也就是說我們只能也必須將流運(yùn)算符重載實(shí)現(xiàn)到全局,才能避免this作第一個(gè)參數(shù)。

我們試試看:

【C++】類和對象(中)之拷貝構(gòu)造與運(yùn)算符、操作符重載,C++,c++,開發(fā)語言

對啊,定義到全局,就訪問不了私有的成員變量了呀。

那這里一般我們會(huì)采用友元函數(shù)解決成員變量私有的問題。(友元函數(shù)會(huì)在后續(xù)介紹)

比如:

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1);
	// 友元函數(shù)
	friend void operator<<(ostream& out, const Date& d);
private:
	int _year;
	int _month;
	int _day;
};

void operator<<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
}

這樣就可以解決類外部的函數(shù)無法訪問到私有成員變量的問題了。?

可是我們在使用時(shí)發(fā)現(xiàn),<<是需要返回值的,比如這種cout<<a<<b<<endl;

那我們修改一下函數(shù)實(shí)現(xiàn):

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1);
	// 友元函數(shù)
	friend ostream& operator<<(ostream& out, const Date& d);
private:
	int _year;
	int _month;
	int _day;
};

ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	return out;
}

?完整的輸入輸出流重載函數(shù):

class Date
{
public:
	Date(int year, int month, int day)	// 構(gòu)造函數(shù)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);
private:
	int _year;
	int _month;
	int _day;
};

ostream& operator<<(ostream& out, const Date& d)
{
	cout << d._year << "/" << d._month << "/" << d._day;
	return out;
}

istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	return in;
}

int main()
{
	int a = 0;
	int b = 1;
	cout << a << " " << b << endl;

	Date d1(2022, 11, 27);
	Date d2(2022, 11, 28);
	cout << d1 << " " << d2 << endl;
	cin >> d2;
	cout << d2;
	return 0;
}

2.4前置++與后置++重載

前置++與后置++的區(qū)別是什么呢?

一個(gè)是先加后用,一個(gè)則是先用后加。

還有另一個(gè)問題,他們的符號都是++,那怎么區(qū)分呢?
C++規(guī)定:后置++重載時(shí)多增加一個(gè)int類型的參數(shù),但調(diào)用函數(shù)時(shí)該參數(shù)不用傳遞,編譯器自動(dòng)傳遞。

我們直接看實(shí)現(xiàn):

class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	// 前置++:返回+1之后的結(jié)果
	// 注意:this指向的對象函數(shù)結(jié)束后不會(huì)銷毀,故以引用方式返回提高效率
	Date& operator++()
	{
		_day += 1;
		return *this;
	}
	// 后置++:
	// 注意:后置++是先使用后+1,因此需要返回+1之前的舊值,故需在實(shí)現(xiàn)時(shí)需要先將this保存一份,然后給this + 1
	// 而temp是臨時(shí)對象,因此只能以值的方式返回,不能返回引用
	Date operator++(int)
	{
		Date temp(*this);
		_day += 1;
		return temp;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d;
	Date d1(2022, 1, 13);
	d = d1++; // d: 2022,1,13 d1:2022,1,14
	d = ++d1; // d: 2022,1,15 d1:2022,1,15
	return 0;
}

3.const成員函數(shù)

將const修飾的“成員函數(shù)”稱之為const成員函數(shù),const修飾類成員函數(shù),實(shí)際修飾該成員函數(shù)隱含的this指針,表明在該成員函數(shù)中不能對類的任何成員進(jìn)行修改。

比如這樣:

【C++】類和對象(中)之拷貝構(gòu)造與運(yùn)算符、操作符重載,C++,c++,開發(fā)語言


?觀察下面的代碼:

class Date
{
public:
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << "Print()" << endl;
		cout << "year:" << _year << endl;
		cout << "month:" << _month << endl;
		cout << "day:" << _day << endl << endl;
	}
	void Print() const
	{
		cout << "Print()const" << endl;
		cout << "year:" << _year << endl;
		cout << "month:" << _month << endl;
		cout << "day:" << _day << endl << endl;
	}
private:
	int _year; // 年
	int _month; // 月
	int _day; // 日
};
void Test()
{
	Date d1(2022, 1, 13);
	d1.Print();
	const Date d2(2022, 1, 13);
	d2.Print();
}

請思考下面的幾個(gè)問題:
1. const對象可以調(diào)用非const成員函數(shù)嗎?
2. 非const對象可以調(diào)用const成員函數(shù)嗎?
3. const成員函數(shù)內(nèi)可以調(diào)用其它的非const成員函數(shù)嗎?
4. 非const成員函數(shù)內(nèi)可以調(diào)用其它的const成員函數(shù)嗎??


?之前在學(xué)習(xí)引用時(shí),我們曾經(jīng)討論過權(quán)限縮小和放大的問題??樊梓慕-引用

權(quán)限只能縮小,不能放大。

??解釋一下??

也就是說const的對象在引用時(shí),引用須加const,如果不加,此時(shí)引用的權(quán)限大于被引用的const對象,這就是所謂的權(quán)限不能放大。

但是不加const的對象在引用時(shí),引用可加可不加const,因?yàn)闄?quán)限是平級或是縮小了的,這就是所謂的權(quán)限只能縮小。


那搞清楚了這個(gè)概念,再看前面的題目有沒有思路了呢?

答案:

  1. ?權(quán)限被放大;
  2. ?權(quán)限被縮??;
  3. ?權(quán)限被放大;
  4. ?權(quán)限被縮小;

??????成員函數(shù)定義的原則??????

  1. 能定義成const的成員函數(shù)都應(yīng)該定義成const(這里的const是指參數(shù)列表后面的const,也就是修飾this的const),這樣const對象和非const對象(這里的const是指修飾對象的類型為const)都可以調(diào)用;比如下面圖片,屬于const對象調(diào)用非const成員函數(shù),我們剛做的小題已經(jīng)告訴我們這樣是權(quán)限放大的問題了,所以現(xiàn)在只需要將成員函數(shù)設(shè)計(jì)為const成員函數(shù),將this的類型改為const Date* const this,就可以解決這一問題。

    【C++】類和對象(中)之拷貝構(gòu)造與運(yùn)算符、操作符重載,C++,c++,開發(fā)語言

  2. 要修改成員變量的成員函數(shù),不能定義成const。

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

這兩個(gè)默認(rèn)成員函數(shù)一般不用重新定義,編譯器默認(rèn)生成。

class Date
{
public:
	Date* operator&()
	{
		return this;
	}
	const Date* operator&()const
	{
		return this;
	}
private:
	int _year; // 年
	int _month; // 月
	int _day; // 日
};

這兩個(gè)運(yùn)算符一般不需要重載,使用編譯器生成的默認(rèn)取地址的重載即可,只有特殊情況,才需要重載,比如想讓別人獲取到指定的內(nèi)容!??


5.日期類的實(shí)現(xiàn)

class Date
{
	// 獲取某年某月的天數(shù)
	int GetMonthDay(int year, int month)
	{
		static int days[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
		int day = days[month];
		if (month == 2
			&& ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
		{
			day += 1;
		}
		return day;
	}
	// 全缺省的構(gòu)造函數(shù)
	Date(int year = 1900, int month = 1, int day = 1)
	{
		if (year < 1900
			|| month < 1 || month > 12
			|| day < 1 || day > GetMonthDay(year, month))
		{
			cout << "非法日期" << endl;
		}
		_year = year;
		_month = month;
		_day = day;
	}
	// 拷貝構(gòu)造函數(shù)
    // d2(d1)
	Date(const Date& d)
	{
		this->_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	// 賦值運(yùn)算符重載
    // d2 = d3 -> d2.operator=(&d2, d3)
	Date& operator=(const Date& d)
	{
		if (this != &d)
		{
			this->_year = d._year;
			this->_month = d._month;
			this->_day = d._day;
		}
		return *this;
	}
	// 析構(gòu)函數(shù)
	~Date()
	{
		// 清理工作
	}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	// 日期+=天數(shù)
    // d1 += 10
    // d1 += -10
	Date& operator+=(int day)
	{
		if (day < 0)
		{
			return *this -= -day;
		}
		_day += day;
		while (_day > GetMonthDay(_year, _month))
		{
			_day -= GetMonthDay(_year, _month);
			_month++;
			if (_month == 13)
			{
				_year++;
				_month = 1;
			}
		}
		return *this;
	}
	// 日期+天數(shù)
    // d + 10
	Date operator+(int day)
	{
		Date ret(*this);
		ret += day;
		return ret;
	}
	// 日期-天數(shù)
	Date operator-(int day)
	{
		Date ret(*this);
		ret -= day;
		return ret;
	}

	// 日期-=天數(shù)
	// d -= 100
	// d -= -100
	Date& operator-=(int day)
	{
		if (day < 0)
		{
			return *this += -day;
		}
		_day -= day;
		while (_day <= 0)
		{
			--_month;
			if (_month == 0)
			{
				--_year;
				_month = 12;
			}
			_day += GetMonthDay(_year, _month);
		}
		return *this;
	}
	// 前置++
	// ++d -> d.operator++(&d)
	Date& operator++()
	{
		*this += 1;
		return *this;
	}
	// 后置++
	// d++ -> d.operator++(&d, 0)
	Date operator++(int)
	{
		Date ret(*this);
		*this += 1;
		return ret;
	}
	// // 后置--
	Date operator--(int)
	{
		Date ret(*this);
		*this -= 1;
		return ret;
	}
	// 前置--
	Date& operator--()
	{
		*this -= 1;
		return *this;
	}
	// d1 > d2
	// >運(yùn)算符重載
	bool operator>(const Date& d)
	{
		if (_year > d._year)
		{
			return true;
		}
		else if (_year == d._year)
		{
			if (_month > d._month)
			{
				return true;
			}
			else if (_month == d._month)
			{
				if (_day > d._day)
				{
					return true;
				}
			}
		}
		return false;
	}
	// ==運(yùn)算符重載
	bool operator==(const Date& d)
	{
		return _year == d._year
			&& _month == d._month
			&& _day == d._day;
	}
	// 下面復(fù)用上面兩個(gè)的實(shí)現(xiàn)
	// >=運(yùn)算符重載
	bool operator >= (const Date& d)
	{
		return *this > d || *this == d;
	}
	// <運(yùn)算符重載
	bool operator < (const Date& d)
	{
		return !(*this >= d);
	}
	// <=運(yùn)算符重載
	bool operator <= (const Date& d)
	{
		return !(*this > d);
	}
	// !=運(yùn)算符重載
	bool operator != (const Date& d)
	{
		return !(*this == d);
	}
	// d1 - d2
	// 日期-日期 返回天數(shù)
	int operator-(const Date& d)
	{
		int flag = 1;
		Date max = *this;
		Date min = d;
		if (*this < d)
		{
			max = d;
			min = *this;
			flag = -1;
		}
		int day = 0;
		while (min < max)
		{
			++(min);
			++day;
		}
		return day * flag;
	}
private:
	int _year;
	int _month;
	int _day;
};

這里需要注意的點(diǎn)是:已經(jīng)實(shí)現(xiàn)了的運(yùn)算符重載可以復(fù)用,邏輯轉(zhuǎn)化就好了,沒必要每一個(gè)都要完全實(shí)現(xiàn)。


最近的內(nèi)容很碎,大家只需要跟著博主一起慢慢學(xué)習(xí)就好,內(nèi)容完全展開后就豁然開朗啦


=========================================================================

如果你對該系列文章有興趣的話,歡迎持續(xù)關(guān)注博主動(dòng)態(tài),博主會(huì)持續(xù)輸出優(yōu)質(zhì)內(nèi)容

??博主很需要大家的支持,你的支持是我創(chuàng)作的不竭動(dòng)力??

??~ 點(diǎn)贊收藏+關(guān)注 ~??

=========================================================================?文章來源地址http://www.zghlxwxcb.cn/news/detail-742747.html

到了這里,關(guān)于【C++】類和對象(中)之拷貝構(gòu)造與運(yùn)算符、操作符重載的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

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

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【C++學(xué)習(xí)】類和對象 | 拷貝構(gòu)造 | 探索拷貝構(gòu)造函數(shù)為什么需要引用傳參 | 深拷貝 | 初識運(yùn)算符重載

    【C++學(xué)習(xí)】類和對象 | 拷貝構(gòu)造 | 探索拷貝構(gòu)造函數(shù)為什么需要引用傳參 | 深拷貝 | 初識運(yùn)算符重載

    上一篇文章我們開始學(xué)習(xí)類內(nèi)的默認(rèn)成員函數(shù), 這里是傳送門,有興趣可以去看看:http://t.csdn.cn/iXdpH 這篇文章我們繼續(xù)來學(xué)習(xí)類和對象的知識。 目錄 寫在前面: 1. 拷貝構(gòu)造 2. 拷貝構(gòu)造函數(shù)為什么需要引用傳參? 3. 深拷貝 4. 初識運(yùn)算符重載 寫在最后: 我們在創(chuàng)建一個(gè)對

    2024年02月11日
    瀏覽(24)
  • 【C++初階】四、類和對象(構(gòu)造函數(shù)、析構(gòu)函數(shù)、拷貝構(gòu)造函數(shù)、賦值運(yùn)算符重載函數(shù))

    【C++初階】四、類和對象(構(gòu)造函數(shù)、析構(gòu)函數(shù)、拷貝構(gòu)造函數(shù)、賦值運(yùn)算符重載函數(shù))

    ========================================================================= 相關(guān)代碼gitee自取 : C語言學(xué)習(xí)日記: 加油努力 (gitee.com) ?========================================================================= 接上期 : 【C++初階】三、類和對象 (面向過程、class類、類的訪問限定符和封裝、類的實(shí)例化、類對象模

    2024年02月05日
    瀏覽(32)
  • c++類和對象(拷貝構(gòu)造、運(yùn)算符重載、初始化列表、靜態(tài)成員、友元等)

    c++類和對象(拷貝構(gòu)造、運(yùn)算符重載、初始化列表、靜態(tài)成員、友元等)

    拷貝構(gòu)造函數(shù)的特征: 1、拷貝構(gòu)造函數(shù)是構(gòu)造函數(shù)的一個(gè)重載形式; 2、拷貝構(gòu)造函數(shù)的參數(shù)只有一個(gè)且必須是同類類型對象的引用, 使用傳值方式編譯器直接報(bào)錯(cuò) ,因?yàn)闀?huì)引發(fā)無窮遞歸調(diào)用。 在c++中自定義類型 傳值傳參 的時(shí)候要調(diào)用拷貝構(gòu)造函數(shù)。 3、若未顯式定義,

    2024年02月15日
    瀏覽(26)
  • 【C++】類和對象③(類的默認(rèn)成員函數(shù):拷貝構(gòu)造函數(shù) | 賦值運(yùn)算符重載)

    【C++】類和對象③(類的默認(rèn)成員函數(shù):拷貝構(gòu)造函數(shù) | 賦值運(yùn)算符重載)

    ?? 個(gè)人主頁: Forcible Bug Maker ?? 專欄: C++ 目錄 前言 拷貝構(gòu)造函數(shù) 概念 拷貝構(gòu)造函數(shù)的特性及用法 賦值運(yùn)算符重載 運(yùn)算符重載 賦值運(yùn)算符重載 結(jié)語 本篇主要內(nèi)容:類的6個(gè)默認(rèn)成員函數(shù)中的 拷貝構(gòu)造函數(shù) 和 賦值運(yùn)算符重載 在上篇文章中我們講到了類的默認(rèn)成員函數(shù)的

    2024年04月17日
    瀏覽(29)
  • 【C++初階】類與對象:6大默認(rèn)成員函數(shù)------拷貝構(gòu)造和賦值運(yùn)算符重載

    【C++初階】類與對象:6大默認(rèn)成員函數(shù)------拷貝構(gòu)造和賦值運(yùn)算符重載

    ? 拷貝構(gòu)造函數(shù): 只有單個(gè)形參,該形參是對本類類型對象的引用(一般常用const修飾) ,在用已存在的類類型對象創(chuàng)建新對象時(shí)由編譯器自動(dòng)調(diào)用。 1. 拷貝構(gòu)造函數(shù)是 構(gòu)造函數(shù)的一個(gè)重載形式 ; 2. 拷貝構(gòu)造函數(shù)的 參數(shù)只有一個(gè)且必須是類類型對象的引用 ,使用傳值方式編

    2024年02月03日
    瀏覽(26)
  • c++拷貝構(gòu)造與賦值運(yùn)算符重載

    c++拷貝構(gòu)造與賦值運(yùn)算符重載

    目錄 目錄: ? ? ? ? 1:拷貝構(gòu)造 ? ? ? ? 2:賦值運(yùn)算符重載 ???????? ? ? ? ? 前言:在上一章我們已經(jīng)學(xué)習(xí)過了,構(gòu)造與析構(gòu)這兩個(gè)默認(rèn)成員函數(shù)了,接下來讓我們一起來學(xué)習(xí)另外兩個(gè)重要的默認(rèn)成員函數(shù)。 ? ? ? ? 首先讓我們來講一下默認(rèn)成員函數(shù)這個(gè)概念,所謂

    2024年02月08日
    瀏覽(25)
  • C++拷貝構(gòu)造函數(shù)與賦值運(yùn)算符重載

    C++拷貝構(gòu)造函數(shù)與賦值運(yùn)算符重載

    顧得泉: 個(gè)人主頁 個(gè)人專欄: 《Linux操作系統(tǒng)》?《C++從入門到精通》??《LeedCode刷題》 鍵盤敲爛,年薪百萬! ???????在現(xiàn)實(shí)生活中,可能存在一個(gè)與你一樣的自己,我們稱其為雙胞胎。 ???????那在創(chuàng)建對象時(shí),可否創(chuàng)建一個(gè)與已存在對象一某一樣的新對象呢? ?

    2024年02月22日
    瀏覽(21)
  • 【C++】:拷貝構(gòu)造函數(shù)和賦值運(yùn)算符重載

    【C++】:拷貝構(gòu)造函數(shù)和賦值運(yùn)算符重載

    拷貝構(gòu)造函數(shù)是特殊的構(gòu)造函數(shù)。 是用一個(gè)已經(jīng)存在的對象,賦值拷貝給另一個(gè)新創(chuàng)建的已經(jīng)存在的對象 。 本質(zhì):用同類型的對象拷貝初始化 。 拷貝構(gòu)造函數(shù)也是 特殊的成員函數(shù) ,其特征如下: 2.1 拷貝構(gòu)造函數(shù)是構(gòu)造函數(shù)的一個(gè)重載形式。 2.2 拷貝構(gòu)造函數(shù)的 函數(shù)名域

    2024年04月28日
    瀏覽(28)
  • 【C++】構(gòu)造函數(shù),析構(gòu)函數(shù),拷貝構(gòu)造,運(yùn)算符重載,const 成員

    默認(rèn)成員函數(shù):如果不顯示,編譯器默認(rèn)生成 構(gòu)造函數(shù):是一個(gè)特殊的 成員函數(shù) ,函數(shù)名與類名相同,專門用于 初始化類對象 函數(shù)名與類名相同 無返回值 ,沒有被聲明為void類型 對象實(shí)例化時(shí) 編譯器自動(dòng)調(diào)用 , Date d1 ,或 Date d2(2023, 4, 21) 構(gòu)造函數(shù)可以重載,一個(gè)類中可以

    2023年04月24日
    瀏覽(25)
  • 【C++】C++入門—初識構(gòu)造函數(shù) , 析構(gòu)函數(shù),拷貝構(gòu)造函數(shù),賦值運(yùn)算符重載

    【C++】C++入門—初識構(gòu)造函數(shù) , 析構(gòu)函數(shù),拷貝構(gòu)造函數(shù),賦值運(yùn)算符重載

    如果一個(gè)類中什么成員都沒有,簡稱為空類。 空類中真的什么都沒有嗎? 并不是 任何類在什么都不寫時(shí),編譯器會(huì)自動(dòng)生成以下6個(gè)默認(rèn)成員函數(shù)。 默認(rèn)成員函數(shù):用戶沒有顯式實(shí)現(xiàn),編譯器會(huì)生成的成員函數(shù)稱為默認(rèn)成員函數(shù) 我們實(shí)現(xiàn)了,編譯器就不會(huì)生成了 構(gòu)造函數(shù)是

    2024年02月21日
    瀏覽(27)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包