[Árbol de habilidades de C++] Hacer que los operadores regulares se usen en las clases: seis funciones miembro de las clases II

inserte la descripción de la imagen aquí

Hola, este es Ppeua. Por lo general, actualizo principalmente el lenguaje C, C ++, algoritmo de estructura de datos ... ¡Sígueme si estás interesado! Usted no será decepcionado.


inserte la descripción de la imagen aquí

0. Sobrecarga de operadores

Para mejorar la legibilidad del código, se agrega la sobrecarga de operadores en C++, al igual que la sobrecarga de otras funciones. Su formato de nomenclatura es el siguiente:

operador de tipo de retorno operador (lista de parámetros)

Date operator<(Date&d1)

Pero no todos los operadores se pueden sobrecargar:

  1. No es posible personalizar un operador nuevo, como @
  2. .* :: sizeof ?: .Los operadores anteriores no se pueden sobrecargar, especialmente el primero.*

A continuación, definimos una clase de fecha como una práctica de sobrecarga de operadores:

class Date{
    
    
public:
    Date(int day=1,int month=1,int year=1)
    {
    
    
        if(month>0&&month<13&&day>0&&day<getmonth(year,month))
            _day=day,_month=month,_year=year;
        else
            cout<<"输入错误";
    }

    Date(const Date&d)
    {
    
    
        _day=d._day;
        _month=d._month;
        _year=d._year;
        cout<<"copy";
    }
private:
    int _year;
    int _month;
    int _day;
}

Esta es la función de clase más básica, que incluye un constructor predeterminado y un constructor de copia . El constructor de copia generará: "copiar" cuando se llame, lo que nos ayudará a analizar la función más adelante.

1. Operador de asignación = sobrecargado

Echemos un vistazo a cómo lo define. También se ajusta a la regla de definición anterior:

 Date& operator=(const Date&d)
    {
    
    
        _day=d._day;
        _month=d._month;
        _year=d._year;
        return *this;
    }

¿Por qué necesitamos llamar por valor de retorno? Porque puede ahorrar espacio. Los parámetros se pasan por referencia y el valor devuelto no necesita llamar al constructor de copia

¿No es este un parámetro formal? ¿Por qué se puede hacer referencia al alcance? * esto en sí mismo es un parámetro formal, pero apunta al objeto de fecha, y su marco de pila se almacena en la función principal, por lo que se destruirá y el objeto al que apunta se devolverá y no se destruirá

Agregar const es solo un seguro, por lo que no cambiaremos los parámetros pasados ​​​​en

Podemos demostrarlo con un fragmento de código:

class Date{
    
    
    
public:
    
   
    Date(int day=1,int month=1,int year=1)
    {
    
    
        if(month>0&&month<13&&day>0&&day<getmonth(year,month))
            _day=day,_month=month,_year=year;
        else
            cout<<"输入错误";
    }

    Date(const Date &d)
    {
    
    
        _day=d._day;
        _month=d._month;
        _year=d._year;
        cout<<"copy";
    }

    Date& operator=(const Date &d)
    {
    
    
        _day=d._day;
        _month=d._month;
        _year=d._year;
        return *this;
    }
int main()
{
    
     
    Date d1(2,5,2024);
    Date d2;
    d2=d1;
}

Primero elimine ambas referencias, y encontrará que la construcción de copia se llama dos veces, que son el paso de valor y el valor de retorno, respectivamente :

inserte la descripción de la imagen aquí

** Después de agregar, la construcción de la copia no se llamará, por lo que escribir de esta manera ahorra espacio y tiempo. **Durante la fase de compilación, el código modificado se transformará en

d2.operator=(d1)

Esto también es conveniente para que entendamos el método de ejecución específico de este operador.

¿En cuanto a por qué necesita devolver el tipo de fecha? Considere el siguiente escenario:

int a;
int b;
int c;
a=b=c=1;

La esencia de esta operación de código es:
inserte la descripción de la imagen aquí

Por lo tanto, debemos hacer que devuelva el tipo de fecha para cumplir con esta situación:

int main()
{
    
    
     
    Date d1(2,5,2024);
    Date d2;
    Date d3;
    d3=d2=d1;
}

Si el operador de asignación no está definido por sí mismo, el sistema generará automáticamente un operador de asignación (esto es lo mismo que el constructor, el constructor de copia y el destructor mencionados anteriormente), y sus reglas de llamada son las mismas que antes. definición, el tipo integrado se completa Copia superficial, el tipo personalizado llama a su operador de asignación personalizado sobrecarga , por lo que es lo mismo que llamar al constructor de copia, y el tipo integrado que implica la gestión del espacio, necesitamos definir el constructor de copia por nosotros mismosEsto también lleva al hecho de que los operadores de asignación no se pueden definir globalmente, sino solo en clases., si define uno globalmente, entrará en conflicto con el definido en la clase.

2. Operador de comparación == sobrecarga

bool operator==(const Date&d)const
    {
    
    
        if(_year==d._year&&_month==d._month&&_day==d._day)
        {
    
    
            return true;
        }
        return false;
    }

Si los tres son iguales, devuelve verdadero, de lo contrario, devuelve falso.La lógica general es fácil de entender. Esta función no es una función predeterminada, por lo que podemos definirla globalmente o definirla en una clase.

Si la definición es global, habrá un problema de que no se puede acceder a los miembros privados de la clase (esto se resolverá más adelante, pero ahora lo ponemos en la clase para evitar este problema)

Entonces, ¿por qué esta const se coloca afuera? Aquí hay una modificación del puntero this, que es la ontología, porque el puntero this existe implícitamente, y no cambiaremos el cuerpo en esta sobrecarga, así que agregue una modificación.

La apariencia original de este puntero: el contenido al que apunta este puntero no se puede cambiar, pero se puede cambiar su valor

Date * const this

Ahora, después de la modificación: no se puede cambiar ni el contenido señalado por este puntero ni su valor, lo que juega un papel protector

const Date * const this 

3. Operador de comparación != Sobrecarga

 bool operator!=(const Date&d)const
    {
    
    
        if(*this==d)return false;
        return true;
    }

Los resultados anteriores se reutilizan directamente aquí, lo que también demuestra el poder del operador sobrecargado hhhh

4. Operador de comparación < sobrecarga

 bool operator<(const Date &d)const
    {
    
    
        if(_year<d._year)
        {
    
    
            return true;
        }
        if(_year==d._year&&_month<d._month)
        {
    
    
            return true;
        }
        if(_year==d._year&&_month==d._month&&_day<d._day)
        {
    
    
            return true;
        }
        return false;  
    }

Principalmente para la implementación de la lógica:

  1. Si el año es joven, devuelve verdadero directamente
  2. Si el año es el mismo y el mes es más pequeño, devuelve verdadero directamente
  3. Si el año y el mes son iguales y el número de días es pequeño, devuelve true directamente

Si no se cumplen las condiciones anteriores, significa que no es menor que, luego devuelve falso directamente

5. Operador de comparación <= sobrecarga

 bool operator<=(const Date &d)const
    {
    
    
        return *this<d||*this==d;
    }

También es una reutilización de == y < escrito antes.Si es menor o igual que, es menor o igual que

6. Operador de comparación > Sobrecarga

bool operator>(const Date &d)const
{
    
    
     return (!(*this<d)&&(*this!=d))?true:false;
}

Si no es menor que y no igual a, menor que o igual a

7. Operador de comparación >= sobrecarga

bool operator>=(const Date &d)const
    {
    
    
        return !(*this<d);
    }

Si no es menor, mayor o igual que

8. Operador de asignación += y + sobrecarga

En la aplicación de la próxima sobrecarga, con el fin de facilitar la obtención de la fecha específica de cada mes, incluyendo el juicio de año bisiesto y año normal. Se implementa una función getmonth en la clase para devolver el número específico de días de cada mes.

int getmonth(int year,int month)
    {
    
    
        static int monthday[13]={
    
    0,31,28,31,30,31,30,31,31,30,31,30,31};
        if((year%4==0&&year%100!=0)||year%400==0)
        {
    
    
            if(month==2)return 29;
        }
        return monthday[month];
    }

Ingrese el año y el mes para juzgar el número de fecha específico, entre los cuales el año bisiesto se encuentra con el bisiesto de cuatro años, el bisiesto de cien años y el bisiesto de cuatrocientos años

A continuación, implemente +=: aquí debe juzgar primero que si Day<0, es equivalente a calcular *this-=Day

Date& operator+=(int Day)
    {
    
    
    	if(Day<0)
        {
    
    
            *this-=(-Day);
            return *this;
        }
        _day+=Day;
        while(_day>getmonth(_year,_month))
        {
    
    
            _day-=getmonth(_year,_month);
            ++_month;
            if(_month>12)
            {
    
    
                _month=1;
                _year++;
            }
        }
        return *this;
    }

La lógica de implementación específica es la siguiente:
inserte la descripción de la imagen aquí

Así que veamos la lógica de +:

Date operator+(int day)
    {
    
    
        Date tmp=*this;
        tmp+=day;
        tmp.print();
        return tmp;
    }

Para no cambiar el objeto Fecha en sí, debe hacer una copia de la Fecha ( aquí use el constructor de copia, no la sobrecarga del operador de asignación, porque se asigna cuando se inicializa el objeto ), luego reutilice +=, y finalmente devolverse a sí mismo Debido a que son parámetros locales, por lo que las referencias no se pueden devolver, porque tmp se destruirá cuando salga del alcance .

9. Operador de asignación -= y - sobrecarga:

-= :

 Date& operator-=(const int Day)
    {
    
    
        if(Day<0)
        {
    
    
            *this+=(-Day);
            return *this;
        }
        _day-=Day;
        while(_day<=0)
        {
    
    
            --_month;
            if(_month<1)
            {
    
    
                _year--;
                _month=12;
            }
            _day+=getmonth(_year,_month);
        }
        return *this;
    }

-:

Date operator-(const int Day)
    {
    
    
        Date tmp=*this;
        return tmp-=Day;
    }

La lógica general es similar a la de la suma, pero la repetiré aquí.

10. Pre-++ y Post-++

prefijo ++

Date& operator++()
    {
    
    
        *this+=1;
        return *this;
    }

Si quiero realizar una operación ++ en un objeto Fecha, puedo directamente: ++ Fecha.

Post ++ : Para volver a sobrecargar con pre ++, se agrega un parámetro. Este parámetro no jugará ningún papel en el proceso de sobrecarga. Es solo para distinguir qué sobrecarga es específica. Al usarlo, el compilador pasará 0 en la publicación ++ por sí mismo, solo necesitamos usarlo normalmente ,

Date operator++(int)
    {
    
    
        Date tmp=*this;
        *this+=1;
        return tmp;
    }

Cuando estaba aprendiendo C, siempre veía discusiones sobre pre-++ y post-++. Ahora puedo ver la sobrecarga, porque post-++ copiará una copia del valor original, por lo que la eficiencia será menor.

Sin embargo, en los tipos incorporados, esta transformación de eficiencia es insignificante .

11. Delantero y trasero

 Date& operator--()
    {
    
    
        *this-=1;
        return *this;
    }

    Date operator--(int)
    {
    
    
        Date tmp;
        *this-=1;
        return tmp;
    }

12. Operador lógico - sobrecarga

Para restar entre dos clases de fechas, calcule la diferencia entre fechas

int operator-(Date &d)
    {
    
    
        Date max=*this;
        Date min=d;
        int flag=1;
        if(max<min)
        {
    
    
            max=d;
            min=*this;
            flag=-1;
        }
        int n=0;
        while(min!=max)
        {
    
    
            ++min;
            ++n;
        }
        return n*flag;
    }

Encuentre primero la fecha más grande y acérquese a la mayor cantidad de días paso a paso combinando el ++ más pequeño y contando los días ++, y finalmente regrese. Tenga en cuenta que pasar los valores necesita pasar las referencias para mejorar la eficiencia

13. Sobrecarga del operador de flujo

¿Por qué cout/cin en c++ puede generar/entrar objetos de cualquier tipo incorporado sin el tipo de objeto? Porque cout y cin también son un objeto de flujo en c++, y la capa subyacente implementa múltiples tipos de sobrecarga

Esta sobrecarga debe definirse en el global. Si se define en la clase, de acuerdo con la regla de conversión anterior, se convertirá en d1<<cout, pero si se define en el global, habrá casos en los que las variables privadas no pueden ser accedido, por lo que proporcionamos una función de Declaración de un amigo.

  friend ostream& operator<<(ostream& out,const Date&d);
  friend istream& operator>>(istream& in, Date&d);

Se puede colocar en cualquier parte de la clase, lo que indica que esta función es amiga de esta clase y puede acceder directamente a las variables y funciones que contiene (el significado específico de amigos se explicará en detalle más adelante).

13.1 Sobrecarga del flujo de salida:

ostream& operator<<(ostream& out,const Date&d)
{
    
    
   out<<"day: "<<d._day<<" month: "<<d._month<<" year: "<<d._year<<endl;
   return out;
}

ostream es un objeto de flujo de salida, y su valor de retorno se colocará en el flujo de salida en la salida

13.2 Sobrecarga del flujo de entrada:

istream& operator>>(istream& in,Date&d)
{
    
    
   	int year, month, day;
	in >> day >> month >>year;

	if (month > 0 && month < 13
		&& day > 0 && day <= d.getmonth(year, month))
	{
    
    
		d._year = year;
		d._month = month;
		d._day = day;
	}
	else
	{
    
    
		cout << "非法日期" << endl;
	}
	return in;
}

En general igual que el anterior

14. Código completo:

#include<iostream>
using namespace std;
class Date{
    
    
    
public:
    
    friend ostream& operator<<(ostream& out,const Date&d);
    friend istream& operator>>(istream& in, Date&d);
   
    Date(int day=1,int month=1,int year=1)
    {
    
    
        if(month>0&&month<13&&day>0&&day<getmonth(year,month))
            _day=day,_month=month,_year=year;
        else
            cout<<"输入错误";
    }

    Date(const Date&d)
    {
    
    
        _day=d._day;
        _month=d._month;
        _year=d._year;
        cout<<"copy"<<endl;
    }

    int getmonth(int year,int month)
    {
    
    
        static int monthday[13]={
    
    0,31,28,31,30,31,30,31,31,30,31,30,31};
        if((year%4==0&&year%100!=0)||year%400==0)
        {
    
    
            if(month==2)return 29;
        }
        return monthday[month];
    }

    void print()
    {
    
    
        cout<<"day: "<<_day<<" month: "<<_month<<" year: "<<_year<<endl;
    }


    Date operator=(const Date d)
    {
    
    
        _day=d._day;
        _month=d._month;
        _year=d._year;
        return *this;
    }


    Date& operator+=(int Day)
    {
    
    
        if(Day<0)
        {
    
    
            *this-=(-Day);
            return *this;
        }
        _day+=Day;
        while(_day>getmonth(_year,_month))
        {
    
    
            _day-=getmonth(_year,_month);
            ++_month;
            if(_month>12)
            {
    
    
                _month=1;
                _year++;
            }
        }
        return *this;
    }
    Date operator+(int day)
    {
    
    
        Date tmp=*this;
        tmp+=day;
        tmp.print();
        return tmp;
    }
    Date& operator++()
    {
    
    
        *this+=1;
        return *this;
    }
    Date operator++(int)
    {
    
    
        Date tmp=*this;
        *this+=1;
        return tmp;
    }

    int operator-(Date &d)
    {
    
    
        Date max=*this;
        Date min=d;
        int flag=1;
        if(max<min)
        {
    
    
            max=d;
            min=*this;
            flag=-1;
        }
        int n=0;
        while(min!=max)
        {
    
    
            ++min;
            ++n;
        }
        return n*flag;
    }
    
    Date& operator-=(const int Day)
    {
    
    
        if(Day<0)
        {
    
    
            *this+=(-Day);
            return *this;
        }
        _day-=Day;
        while(_day<=0)
        {
    
    
            --_month;
            if(_month<1)
            {
    
    
                _year--;
                _month=12;
            }
            _day+=getmonth(_year,_month);
        }
        return *this;
    }
    
    Date operator-(const int Day)
    {
    
    
        Date tmp=*this;
        return tmp-=Day;
    }

    Date& operator--()
    {
    
    
        *this-=1;
        return *this;
    }

    Date operator--(int)
    {
    
    
        Date tmp;
        *this-=1;
        return tmp;
    }



    bool operator==(const Date&d)const
    {
    
    
        if(_year==d._year&&_month==d._month&&_day==d._day)
        {
    
    
            return true;
        }
        return false;
    }
    bool operator!=(const Date&d)const
    {
    
    
        if(*this==d)return false;
        return true;
    }
    bool operator<(const Date &d)const
    {
    
    
        if(_year<d._year)
        {
    
    
            return true;
        }
        if(_year==d._year&&_month<d._month)
        {
    
    
            return true;
        }
        if(_year==d._year&&_month==d._month&&_day<d._day)
        {
    
    
            return true;
        }
        return false;  
    }

    bool operator<=(const Date &d)const
    {
    
    
        return *this<d||*this==d;
    }

    bool operator>(const Date &d)const
    {
    
    
        return (!(*this<d)&&(*this!=d))?true:false;
    }
    bool operator>=(const Date &d)const
    {
    
    
        return !(*this<d);
    }


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

ostream& operator<<(ostream& out,const Date&d)
{
    
    
   out<<"day: "<<d._day<<" month: "<<d._month<<" year: "<<d._year<<endl;
   return out;
}

istream& operator>>(istream& in,Date&d)
{
    
    
   	int year, month, day;
	in >> day >> month >>year;

	if (month > 0 && month < 13
		&& day > 0 && day <= d.getmonth(year, month))
	{
    
    
		d._year = year;
		d._month = month;
		d._day = day;
	}
	else
	{
    
    
		cout << "非法日期" << endl;
	}
	return in;
}

int main()
{
    
    
     
    Date d1(2,5,2024);
    d1+=100;
    d1.print();
}

Hasta ahora, la clase se ha completado.

15. Dirección de sobrecarga del operador

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

De forma predeterminada, el compilador generará automáticamente esta sobrecarga y no es necesario escribir esta sobrecarga en la mayoría de los casos.

Si no desea que una persona obtenga una dirección modificable, pero solo desea que obtenga una dirección constante no modificable, puede escribir así

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

16. Hasta ahora, las seis funciones integradas de miembros de tipo se han completado

imagen

Supongo que te gusta

Origin blog.csdn.net/qq_62839589/article/details/130617601
Recomendado
Clasificación