首頁 > 軟體

C++類別中const修飾的成員函數及日期類小練習

2023-01-31 06:01:12

一.const修飾類的成員函數

1.問題引出:

給出一段簡單的程式碼

程式碼段:

#include <iostream>
using std::cin;
using std::cout;
using std::endl;
 
class Date1
{
public:
	Date1(int year = 2000)             類的全預設建構函式(可無參呼叫)
	{
		_year = year;
	}
 
	void Prin()
	{
		cout << "Print Date:" << _year << endl;
	}
 
private:
	int _year;
};
 
 
 
int main()
{
	const Date1 a;                       定義一個const修飾的物件a(該物件只可讀,不可被寫入)
	a.Prin();
 
	return 0;
}

該段程式會編譯報錯:

2.問題分析

上述程式碼段出錯的原因要從類的成員函數的隱含引數this指標出發進行分析:

注意:

  • 由於a是const修飾的物件,因此&a 取出的是 const Date *型別的指標,該指標只可對a物件的記憶體空間進行讀取操作而不可進行寫入操作(該指標的許可權為只可讀取不可寫入)。
  • Prin函數的形參是Date * const this指標,該型別指標同時具有讀取和寫入記憶體空間的許可權。
  • 將&a賦給Prin的形參this,就會使指標的讀寫許可權被放大,因此編譯無法通過(指標是靈活而危險的存在,編譯器只允許其讀寫許可權被縮小而不允許其許可權被放大)

3.const修飾類的成員函數 

我們知道類的每個成員函數都有一個隱含的this指標形參(型別為:類名*const this)。

為了使被const修飾的物件(比如是上面程式碼段中的a)可以呼叫其成員物件,C++規定可以用const來修飾類的成員函數。

類中被const修飾的“成員函數”稱為const成員函數,const修飾類成員函數,本質上修飾該成員函數隱含的this指標,表明在該成員函數中不能對類的任何成員變數進行修改。(修飾後成員函數的this指標形參型別變為:const 類名* const this)

比如:

const修飾的物件不可以呼叫非const修飾的成員函數(類指標傳參給this指標時讀寫許可權被放大):

非const修飾的物件可以呼叫const修飾的成員函數(類指標傳參給this指標時讀寫許可權被縮小):

const修飾的成員函數內不可以呼叫其它的非const修飾的成員函數(this指標之間傳參時讀寫許可權被放大):

非const修飾的成員函數內可以呼叫其它的const修飾的成員函數(this指標之間傳參時讀寫許可權被縮小):

當類的成員函數中沒有對類的成員變數進行任何形式的修改操作時,該成員函數最好都用const來修飾(這樣安全同時又使得const修飾的物件可以呼叫該成員函數)以保證程式碼的健壯性。

二. 類的兩個預設的&運運算元過載

編譯器會預設生成兩個類的&(取地址)過載用於類的取地址操作(如果我們自定義了類的取地址過載則編譯器便不會再生成預設的)

C++中,內建運運算元若要直接作用於類物件則必須經過過載。

若想取到類物件的地址,我們可以對&運運算元進行過載,比如:

#include <iostream>
using std::cin;
using std::cout;
using std::endl;
 
 
 
class Date1
{
public:
    Date1(int year = 2000)
	{
		_year = year;
	}
 
 
	Date1* operator& ()               對&進行過載用於非const修飾的物件的取地址
	{
		return this;
	}
 
	const Date1* operator&() const    對&進行過載用於const修飾的物件的取地址
	{
		return this;
	}
 
private:
	int _year;
};
 
 
int main()
{
	const Date1 a;                     定義一個const修飾的物件a(該物件只可讀,不可被寫入)
    Date1 b;
 
	cout << &a << endl;
	cout << &b << endl;
 
	return 0;
}

這兩個預設成員函數一般不用重新自定義 ,編譯器預設會生成,編譯其預設生成的&過載和上面我們自定義的成員函數應該沒有什麼區別(至少功能上沒區別)。

三. 日期類小練習 

日期類標頭檔案:

為了提高程式碼的可維護性和可讀性,將日期類的成員函數的宣告和定義分開寫。

#pragma once
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
 
//記錄日期的類
class Date        
{
public:
 
	//Date的建構函式
	Date(int day=1, int month=1, int year=1);		
	//獲取月份天數的方法
	int GetMonthday(const int month) const;
	//類物件的日期列印函數
	void Print() const;
	//判斷某個日期是星期幾,並列印出來
	void GetWeekDay() const ;
 
 	//一組比較運運算元的過載
	bool operator> (const Date& date)const;				
	bool operator==(const Date& date)const;
	//在邏輯上我們只需定義出大於(或小於)和等於的判斷函數,剩餘的判斷函數我們就可以通過複用的方    
    式簡化程式碼書寫
	bool operator<(const Date& date)const;
	bool operator>=(const Date& date)const;
	bool operator<=(const Date& date)const;
	bool operator!=(const Date& date)const;
 
	//一組日期+(-)整數的操作和+=(-=)整數的操作
	Date operator+(const int day)const;
	Date& operator+=(const int day);
	Date operator-(const int day)const;
	Date& operator-=(const int day);
	Date& operator=(const Date& date);
	
	//一組前置++(--)和後置++(--)的過載
	Date& operator++();								 //實現日期類的前置++
	Date operator++(int);							 //實現日期類的後置++
	Date& operator--();                              //實現日期類的前置--
	Date operator--(int);                            //實現日期類的後置--
 
	//實現時期相減的操作符過載
	int operator-(const Date& date)const;
	
private:
	int _day;
	int _month;
	int _year;
 
};

日期類的成員函數的實現:

#include "Date.h"
 
//Date的建構函式
Date ::Date(int day, int month, int year)   
{
	_day = day;
	_month = month;
	_year = year;
	if (_year <= 0 || _month <= 0 || _month > 12 || _day <= 0 || _day > GetMonthday(_month))
	{
		cout << "date invalued please exit the app" << endl;
		exit(0);
	}
	
}
//獲取相應月份天數的方法
int Date::GetMonthday(const int month)const
{
	static const int arr[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
	int ret = arr[month - 1];
	if (((0 == _year % 4 && 0 != _year % 100) || (0 == _year % 400)) && 2 == month)
	{
		ret++;
	}
	return ret;
}
//類物件的日期列印函數
void Date::Print()const
{
	cout << _year << ' ' << _month << ' ' << _day << ' ' << endl;
}
//判斷某個日期是星期幾,並列印出來
//注意this指標不能由使用者去傳
void Date::GetWeekDay()const
{
	const char* arr[7] = { "星期一","星期二","星期三","星期四","星期五","星期六","星期日" };
	const Date tem(1, 1, 1900);
	const int subret = (*this)-tem;
	printf("%sn", arr[(subret % 7)]);
}
 
//將 > 運運算元進行過載
bool Date ::operator> (const Date& date)const
{
	if (_year > date._year)
	{
		return true;
	}
	else if (_year == date._year && _month > date._month)
	{
		return true;
	}
	else if (_year == date._year && _month == date._month && _day > date._day)
	{
		return true;
	}
	return false;
}
//將 =運運算元進行過載
bool Date:: operator==(const Date& date)const
{
	if (date._day == _day && date._month == _month && date._year == _year)
	{
		return true;
	}
	return false;
}
//在邏輯上我們只需定義出大於(或小於)和等於的判斷函數,剩餘的判斷函數我們就可以通過複用的方式簡化程式碼書寫
bool Date :: operator>= (const Date& date)const
{
	if ((*this) > date || (*this) == date)
	{
		return true;
	}
	return false;
}
 
bool Date :: operator < (const Date& date)const
{
	if ((*this) >= date)
	{
		return false;
	}
	return true;
}
 
bool Date :: operator<=(const Date& date)const
{
	if ((*this) > date)
	{
		return false;
	}
	return true;
}
bool Date:: operator!= (const Date& date)const
{
	if ((*this) == date)
	{
		return false;
	}
	return true;
}
 
//一組日期+(-)整數的操作和+=(-=)整數的操作
Date& Date::operator+=(const int day)
{
	if (day < 0)
	{
		(*this) -= (-day);
		return (*this);
	}
	_day += day;
	while (_day > GetMonthday(_month))
	{
		if (_month < 12)
		{
			_day -= GetMonthday(_month);
			_month++;
		}
		else
		{
			_day -= GetMonthday(_month);
			_year++;
			_month = 1;
		}
	}
	return (*this);
}
Date Date::operator+(const int day)const
{
	Date tem(*this);
	tem += day;
	return tem;
}
 
Date& Date::operator-=(const int day)
{
	if (day < 0)
	{
		(*this) += (-day);
		return (*this);
	}
	_day -= day;
	while (_day <= 0 )
	{
		if (_month > 1)
		{
			_month--;
			_day += GetMonthday(_month);
		}
		else
		{
			_year--;
			_month = 12;
			_day += GetMonthday(_month);
		}
	}
	if (_year <= 0)
	{
		cout << "operation invalued" << endl;
		exit(0);
	}
	return (*this);
}
Date Date::operator-(int day)const
{
	Date tem(*this);
	tem -= (day);
	return tem;
}
Date& Date ::operator=(const Date& date)
{
	if (this != &date)
	{
		_day = date._day;
		_month = date._month;
		_year = date._year;
	}
 
	return (*this);
}
 
//一組前置++(--)和後置++(--)的過載
Date& Date ::operator++()             //實現日期類的前置++
{
	(*this) += 1;
	return (*this);
}
Date Date ::operator++(int)           //實現日期類的後置++
{
	Date tem(*this);
	(*this) += 1;
	return tem;
}
Date& Date:: operator--()             //實現日期類的前置--
{
	(*this) -= 1;
	return (*this);
}
Date Date:: operator--(int)           //實現日期類的後置--
{
	Date tem(*this);
	(*this) -= 1;
	return tem;
}
 
//實現時期相減的操作符過載
int Date::operator-(const Date& date)const
{
	int count = 0;
	Date min;
	if ((*this) < date)
	{
		min = (*this);
		while (min != date)
		{
			min++;
			count++;
		}
		return -count;
	}
	else
	{
		min = date;
		while (min != (*this))
		{
			min++;
			count++;
		}
		return count;
	}
}

總結

到此這篇關於C++類別中const修飾的成員函數及日期類小練習的文章就介紹到這了,更多相關C++類別const修飾的成員函數內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com