Classes et objets C++ (2) - surcharge d'opérateur d'affectation et surcharge d'opérateur d'adresse


Avant-propos :

Ce chapitre apprendra comment implémenter la surcharge d'opérateurs en profondeur grâce à l'implémentation de la classe date . Ce chapitre complètera l'étude des 3 fonctions membres restantes sur les 6 par défaut - la surcharge de l'opérateur d'affectation et la surcharge de l'opérateur de prise d'adresse .

1. Surcharge de l'opérateur

1. Le concept de surcharge d'opérateur

C++Afin d'améliorer la lisibilité du code, la surcharge d'opérateur est introduite . La surcharge d'opérateur est une fonction avec un nom de fonction spécial , et a également son type de valeur de retour, son nom de fonction et sa liste de paramètres. Son type de valeur de retour et sa liste de paramètres sont similaires aux fonctions ordinaires.

  • Nom de la fonction : Le mot-clé operatorest suivi du symbole de l'opérateur qui doit être surchargé .
  • Prototype de fonction :
  • 返回值类型 operator操作符(参数列表)
  • bool operator==(Date d1,Date d2);

il faut savoir c'est :

  1. De nouveaux opérateurs ne peuvent pas être créés en concaténant d'autres symboles : par ex.operator@
  2. Un opérateur surchargé doit avoir un paramètre de type de classe
  3. Opérateurs pour les types intégrés, dont la signification ne peut pas être modifiée , par exemple : types entiers intégrés +, dont la signification ne peut pas être modifiée
  4. Lorsqu'il est surchargé en tant que fonction membre de classe, ses paramètres formels semblent être inférieurs de 1 au nombre d'opérandes , car le premier paramètre d'une fonction membre est masquéthis
  5. .* :: sizeof ?: .Notez que les 5 opérateurs ci-dessus ne peuvent pas être surchargés . Cela apparaît souvent dans les questions écrites à choix multiples.

2. Implémenter la classe Date

Définissez une classe Date :

class Date
{
    
    
public:
	//构造函数
	Date(int year = 0, int month = 0, int day = 0)
	{
    
    
		//判断日期是否合法
		//GetMonthDay()获取这个月的天数
		if (month > 0 && month < 13 &&
			(day > 0 && day <= GetMonthDay(year, month)))
		{
    
    
				_year = year;
				_month = month;
				_day = day;
		}
		else
		{
    
    
			cout << "日期非法" << endl;
		}
	}
private:
	int _year;//年
	int _month;//月
	int _day;//日
};

Interface de fonction :

// 类里面短小函数,适合做内联的函数,直接是在类里面定义的
class Date
{
    
    
	// 友元函数声明
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);

public:
	// 构造
	Date(int year = 0, int month = 0, int day = 0);
	void Print() const;
	// 当月的天数
	int GetMonthDay(int year, int month) const;
	
	// 重载日期类与日期类运算==, !=, <, <=, >, >=
	bool operator==(const Date& d) const;
	bool operator!=(const Date& d) const;
	bool operator<(const Date& d) const;
	bool operator<=(const Date& d) const;
	bool operator>(const Date& d) const;
	bool operator>=(const Date& d) const;
	
	// 重载日期类与天运算+=, +, -=, -,
	Date& operator+=(int day);
	Date operator+(int day) const;
	Date& operator-=(int day);
	Date operator-(int day) const;

	// 重载日期类与日期类运算-
	int operator-(const Date& d) const;
	
	// 赋值运算符重载
	Date& operator=(const Date& d);

	// 重载日期类前置++--,后置++--
	Date& operator++();
	// int参数 仅仅是为了占位,跟前置重载区分
	Date operator++(int);
	Date& operator--();
	Date operator--(int);

	//取地址重载
	Date* operator&();
	const Date* operator&() const;

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

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

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

Lors de l'implémentation de la surcharge d'opérateurs , une chose nécessite une attention particulière :

La fonction surchargée de l'opérateur binaire a deux paramètres , le premier paramètre est l'opérande gauche et le second paramètre est l'opérande droit .

Dans le chapitre précédent, nous avons parlé des caractéristiques des fonctions membres. Les fonctions membres ont leur propre paramètre this, et le type est un type de classe . Nous pouvons donc omettre le premier paramètre et simplement écrire le deuxième paramètre .

donc:

(1) > < >= <= != surcharge

Implémentez deux fonctions de surcharge d'opérateurs en premier, et les autres peuvent réutiliser les opérateurs déjà implémentés.

class Date
{
    
    
public:
	//构造函数
	//...
	bool operator==(const Date& d)
	{
    
    
		return (_year == d._year) && (_month == d._month) && (_day == d._day);
	}
	bool operator<(const Date& d) 
	{
    
    
		return _year < d._year
			|| (_year == d._year && _month < d._month)
			|| (_year == d._year && _month == d._month && _day < d._day);
	}
	bool operator<=(const Date& d) 
	{
    
    
		//函数的复用
		return *this < d || *this == d;
	}

	bool operator>(const Date& d) 
	{
    
    
		//函数的复用
		return !(*this <= d);
	}

	bool operator>=(const Date& d) 
	{
    
    
		//函数的复用
		return !(*this < d);
	}

	bool operator!=(const Date& d) 
	{
    
    
		//函数的复用
		return !(*this == d);
	}
//...
};

(2) += -= + - surcharge

Remarque : Les opérandes droits des quatre surcharges d'opérateur suivantes sont daydes jours

class Date
{
    
    
public:
	//...
	//获取当月的天数
	int GetMonthDay(int year, int month) 
	{
    
    
		assert(month > 0 && month < 13);

		int monthArray[13] = {
    
     0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
		//判断是否是闰年的二月
		if (month == 2 && 
		((year % 4 == 0 && year % 100 != 0) || (year % 400) == 0))
		{
    
    
			return 29;
		}
		else
		{
    
    
			return monthArray[month];
		}
	}
	//+= 返回自身的引用,减少拷贝
	Date& operator+=(int day)
	{
    
    
		//判断是否加了负数
		if (day < 0)
		{
    
    
			//复用
			*this -= -day;
			return *this;
		}

		_day += day;
		while (_day > GetMonthDay(_year, _month));
		{
    
    
			_day -= GetMonthDay(_year, _month);
			//进位
			_month++;
			if (_month == 13)
			{
    
    
				_year++;
				_month = 1;
			}
		}
		return *this;
	}
	//-= 返回自身的引用,减少拷贝
	Date& operator-=(int day)
	{
    
    
		//判断是否减了一个负数
		if (day < 0)
		{
    
    
			//复用
			*this += -day;
			return *this;
		}

		_day -= day;
		while (_day <= 0)
		{
    
    
			--_month;
			if (_month == 0)
			{
    
    
				--_year;
				_month = 12;
			}

			_day += GetMonthDay(_year, _month);
		}

		return *this;
	}
	Date operator+(int day) 
	{
    
    
		//拷贝构造
		//因为加不改变自身的值,所以创建临时对象
		Date tmp(*this);
		//复用
		tmp += day;
		return tmp;
	}
	Date operator-(int day)
	{
    
    
		Date tmp(*this);
		tmp -= day;
		return tmp;
	}
//...
};

(3) Surcharge pré-++ et post-++

Le préfixe ++et le suffixe ++sont tous deux des opérateurs unaires . La différence entre les deux est :

  • Préposition ++: utilisez-la en premier++ , retournez ++le nombre suivant
  • Arrière ++: utilisez d'abord puis ++retournez ++le numéro précédent

Afin de faire la distinction lors d'une surcharge, C++ stipule :

  • ++Lors de la post- surcharge, ajoutez un intparamètre supplémentaire de type , mais ce paramètre n'a pas besoin d'être passé lors de l'appel, et le compilateur le passera automatiquement.
class Date
{
    
    
public:
	//...
	//前置++
	Date& operator++()
	{
    
    
		*this += 1;
		return *this;
	}
	//后置++
	// 注意:后置++是先使用后+1,因此需要返回+1之前的旧值,
	// 故需在实现时需要先将this保存一份,然后给this + 1
	// 而temp是临时对象,因此只能以值的方式返回,不能返回引用
	Date operator++(int)
	{
    
    
		Date tmp(*this);
		*this += 1;
		return tmp;
	}
	//前置--
	Date& operator--()
	{
    
    
		*this -= 1;
		return *this;
	}
	//后置--
	Date operator--(int)
	{
    
    
		Date tmp(*this);
		*this -= 1;
		return tmp;
	}
//...
};

(4) Date-date de réalisation

Date + date n'a pas de sens, mais date - date est significatif, et date - date représente le nombre de jours entre deux dates

class Date
{
    
    
//...
	int operator-(const Date& d)
	{
    
    
		Date max = *this;
		Date min = d;
		int flag = 1;

		if (*this < d)
		{
    
    
			max = d;
			min = *this;
			flag = -1;
		}

		int n = 0;
		while (min != max)
		{
    
    
			++min;
			++n;
		}

		return n * flag;
	}
	//...
}

(5) << et >> surcharge

Date d1(2023,5,1);
cout<<d1;
  1. <<Et est un opérateur binaire. Comme mentionné ci-dessus , le premier paramètre de>> l'opérateur binaire est l'opérateur gauche et le deuxième paramètre est l'opérateur droit.
  2. Parce que le premier paramètre de la fonction membre dans la classe est this, l'opérande gauche devient l'objet et l'opérande droit devientcout , ce qui est incompatible d1<<coutavec les C++habitudes grammaticales habituelles, donc nous ne pouvons pas écrire <<et >>dans la fonction membre de la classe, mais surchargez-le en dehors de la classe
  3. Mais les fonctions extérieures à la classe ne peuvent pas accéder aux fonctions privées de la classe , nous définissons donc la fonction surchargée comme une fonction amie à atteindre.
class Date
{
    
    
//...
	//申明友元函数
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);
	//...
}
ostream& operator<<(ostream& out, const Date& d)
{
    
    
	out << d._year << "年" << d._month << "月" << d._day << "日";
	return out;
}

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

2. Fonction membre par défaut - surcharge de l'opérateur d'affectation

Comme les fonctions membres par défaut précédentes telles que les constructeurs et les destructeurs , la surcharge d' opérateur d' affectation est également l' une des six fonctions membres par défaut de la classe .

La surcharge des opérateurs d'affectation a les propriétés suivantes :

  1. Format de surcharge de l'opérateur d'affectation :
    type de paramètre : const &T, la référence de paramètre peut améliorer l'efficacité du passage du paramètre
    type de valeur de retour : T&, la référence de la valeur de retour peut améliorer l'efficacité du retour , le but de la valeur de retour est de prendre en charge l'affectation continue et de détecter s'il faut s'attribuer en continu
    Retour *this: la définition de l'affectation continue à composer
  2. Les opérateurs d'affectation ne peuvent être surchargés qu'en tant que fonctions membres de classes et ne peuvent pas être surchargés en tant que fonctions globales ;
class Date
{
    
    
//...
	Date& operator=(const Date& d)
	{
    
    
		if (this != &d)
		{
    
    
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}
	//...
}

2. Fonction membre par défaut - surcharge de l'opérateur d'adresse

Il n'y a que deux des 6 fonctions membres par défaut : prendre la surcharge d'adresse et constprendre la surcharge d'adresse . Cependant, il n'est vraiment pas nécessaire d'implémenter ces deux fonctions, car l'effet de notre propre implémentation et de l'implémentation automatique du compilateur est le même.

class Date
{
    
    
	//...
	Date* operator&()
	{
    
    
		return this;
	}
	const Date* operator&()const
	{
    
    
		return this;
	}
	//...
};

#. Points de connaissance supplémentaires : membres const

constLa fonction membre modifiée est appelée une constfonction membre, constla fonction membre de classe modifiée et le pointeur implicite de la fonction membre réellement modifiée thisindique qu'aucun membre de la classe ne peut être modifié dans la fonction membre .

Par exemple:

class Date
{
    
    
public:
	//...
	void print()
	{
    
    
		cout << _year << "年" << _month << "月" << _day << "日" << endl;
	}
private:
	int _year;
	int _month;
	int _day;
}

void Test3()
{
    
    
	Date d1(2023, 4, 1);
	d1.print();
	const Date d2(2022, 3, 1);
	d2.print();
}

résultat de l'opération :

insérez la description de l'image ici
C'est parce que l'autorité est élargie : on ne peut pas const Date &d2passer au paramètre formel, Date* this
la bonne façon de l'écrire est :

void print() const
{
    
    
	cout << _year << "年" << _month << "月" << _day << "日" << endl;
}

Modification des paramètres implicites qui ne peuvent pas être affichés , donc ajoutez la modification *thisaprès la fonction . constCela convient aux fonctions qui ne modifient pas les variables membres dans les fonctions membres et consts'applique également aux classes non décorées.


C'est la fin de cet article, le texte du code n'est pas facile, s'il vous plaît, soutenez-moi beaucoup !

Je suppose que tu aimes

Origine blog.csdn.net/weixin_67401157/article/details/130527438
conseillé
Classement