Diretório de artigos
Prefácio:
Este capítulo aprenderá como implementar a sobrecarga do operador em profundidade por meio da implementação da classe date . Este capítulo completará o estudo das 3 restantes das 6 funções de membro padrão - sobrecarga do operador de atribuição e sobrecarga do operador de obtenção de endereço .
1. Sobrecarga do operador
1. O conceito de sobrecarga do operador
C++
Para melhorar a legibilidade do código, a sobrecarga de operador é introduzida . A sobrecarga de operador é uma função com um nome de função especial e também tem seu tipo de valor de retorno, nome de função e lista de parâmetros. Seu tipo de valor de retorno e lista de parâmetros são semelhantes às funções comuns.
- Nome da função : A palavra-chave
operator
é seguida pelo símbolo do operador que precisa ser sobrecarregado . - Protótipo da função :
返回值类型 operator操作符(参数列表)
bool operator==(Date d1,Date d2);
deve estar ciente é:
- Novos operadores não podem ser criados concatenando outros símbolos : por exemplo
operator@
- Um operador sobrecarregado deve ter um parâmetro de tipo de classe
- Operadores para tipos integrados, cujo significado não pode ser alterado , por exemplo: tipos inteiros integrados
+
, cujo significado não pode ser alterado - Quando sobrecarregado como uma função de membro de classe, seus parâmetros formais parecem ser 1 a menos que o número de operandos , porque o primeiro parâmetro de uma função de membro está oculto
this
.*
::
sizeof
?:
.
Observe que os 5 operadores acima não podem ser sobrecarregados . Isso geralmente aparece em questões de múltipla escolha por escrito.
2. Implemente a classe Date
Defina uma classe de Data:
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 função:
// 类里面短小函数,适合做内联的函数,直接是在类里面定义的
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;
}
Ao implementar a sobrecarga do operador , uma coisa precisa de atenção especial :
A função sobrecarregada do operador binário tem dois parâmetros , o primeiro parâmetro é o operando esquerdo e o segundo parâmetro é o operando direito .
No capítulo anterior, falamos sobre as características das funções-membro.As funções-membro têm um parâmetro próprio this
e o tipo é um tipo de classe . Assim, podemos omitir o primeiro parâmetro e apenas escrever o segundo parâmetro .
então:
(1) > < >= <= != sobrecarga
Implemente duas funções de sobrecarga de operador primeiro e as outras podem reutilizar os operadores já implementados.
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) += -= + - sobrecarga
Nota: Os operandos certos das quatro sobrecargas de operador a seguir são day
dias
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) Sobrecarga pré-++ e pós-++
O prefixo ++
e o pós-fixo ++
são operadores unários . A diferença entre os dois é:
- Preposição
++
: use primeiro++
, retorne++
o seguinte número - Traseiro
++
: use primeiro e depois++
retorne++
ao número anterior
Para fazer uma distinção ao sobrecarregar, C++ estipula:
++
Ao pós- sobrecarga, adicione umint
parâmetro adicional do tipo , mas esse parâmetro não precisa ser passado ao chamar e o compilador o passará automaticamente.
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) Data-data de realização
Data + data não tem sentido, mas data - data é significativa e data - data representa o número de dias entre duas datas
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) << e >> sobrecarga
Date d1(2023,5,1);
cout<<d1;
<<
E é um operador binário Como mencionado acima , o primeiro parâmetro do>>
operador binário é o operador esquerdo e o segundo parâmetro é o operador direito.- Como o primeiro parâmetro da função de membro na classe é
this
, o operando esquerdo se torna o objeto e o operando direito se tornacout
, o que é inconsistented1<<cout
com osC++
hábitos gramaticais usuais, portanto, não podemos escrever<<
e>>
na função de membro da classe, mas sobrecarregá-la fora da classe - Mas as funções fora da classe não podem acessar as funções privadas da classe , portanto, definimos a função sobrecarregada como uma função amiga a ser alcançada.
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. Função de membro padrão - sobrecarga do operador de atribuição
Como as funções de membro padrão anteriores , como construtores e destruidores , a sobrecarga do operador de atribuição também é uma das seis funções de membro padrão da classe .
A sobrecarga do operador de atribuição tem as seguintes propriedades:
- Formato de sobrecarga do operador de atribuição:
tipo de parâmetro :const &T
, referência de parâmetro pode melhorar a eficiência da passagem de parâmetro
tipo de valor de retorno :T&
, referência de valor de retorno pode melhorar a eficiência de retorno , o objetivo do valor de retorno é oferecer suporte à atribuição contínua e detectar se deve atribuir continuamente a si mesmo
Retorno*this
: a definição de atribuição contínua a ser composta - Os operadores de atribuição só podem ser sobrecarregados como funções de membro de classes e não podem ser sobrecarregados como funções globais ;
class Date
{
//...
Date& operator=(const Date& d)
{
if (this != &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
}
//...
}
2. Função de membro padrão - sobrecarga do operador de endereço
Existem apenas duas das 6 funções de membro padrão - sobrecarga de endereço e const
sobrecarga de endereço . No entanto, realmente não há necessidade de implementar essas duas funções, porque o efeito de nossa própria implementação e da implementação automática do compilador é o mesmo.
class Date
{
//...
Date* operator&()
{
return this;
}
const Date* operator&()const
{
return this;
}
//...
};
#. Pontos de conhecimento suplementares: membros const
const
A função de membro modificada é chamada de const
função de membro, const
a função de membro de classe modificada , e o ponteiro implícito da função de membro realmente modificada this
indica que qualquer membro da classe não pode ser modificado na função de membro .
Por exemplo:
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();
}
resultado da operação:
Isso ocorre porque a autoridade é ampliada : não podemos const Date &d2
passar para o parâmetro formal. Date* this
A maneira correta de escrevê-lo é:
void print() const
{
cout << _year << "年" << _month << "月" << _day << "日" << endl;
}
Parâmetros implícitos de modificação que não podem ser exibidos , portanto, adicione a modificação *this
após a função . const
Isso é adequado para funções que não modificam variáveis de membro em funções de membro e const
também é aplicável a classes não decoradas.
Este é o final deste artigo, o texto do código não é fácil, por favor, me apoie muito!