C++-Klassen und -Objekte (5) – Stream-Operator-Überladung, Konstante und Adressübernahme

Inhaltsverzeichnis

1. Stream-Ausgabe

1. Realisieren Sie eine einzelne Ausgabe

2. Kontinuierliche Ausgabe realisieren

2. Stream-Eingabe

  Zusammenfassen:

3. const-Änderung

4. Holen Sie sich die Adresse

.Get-Adresse und const-Get-Address-Operator überladen

5. [ ] Operatorüberlastung


1. Stream-Ausgabe

1. Realisieren Sie eine einzelne Ausgabe

Erstellen Sie eine Datumsklasse.

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

Wenn wir in der Vergangenheit das Datum in der Datumsklasse ausgeben wollten, mussten wir eine Mitgliedsfunktion für die Ausgabe in der Klasse erstellen.

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

Für integrierte Typen können wir cout<< direkt verwenden, um ihre Werte auszugeben.

Wir können die Stream-Extraktion << auch überladen, um Mitgliedswerte integrierter Typen auszugeben. Lassen Sie uns zunächst den Ursprung von cout verstehen.

  • iostream ist eine Header-Datei in der C++-Standardbibliothek, die die Definition von Stream-Klassen für die Eingabe und Ausgabe enthält. In der Header-Datei iostream sind die beiden Basisklassen istream und ostream definiert, die jeweils für Eingabe- und Ausgabeoperationen verwendet werden.

  • ostream ist eine in der Headerdatei iostream definierte Klasse, die die Basisklasse des Ausgabestreams darstellt. Die Klasse ostream stellt grundlegende Funktionen und Schnittstellen für Ausgabeoperationen bereit. Beispielsweise wird der Operator << verwendet, um Daten an den Stream auszugeben.

  • cout ist ein Objekt der Klasse ostream , bei der es sich um das Standardausgabestreamobjekt handelt. cout -Objekte können den << -Operator verwenden, um Daten an das Standardausgabegerät (normalerweise die Konsole) auszugeben.

iostream ist eine Header-Datei, ostream ist die in iostream definierte Ausgabestream-Basisklasse und cout ist Ein Objekt der Klasse a>  -Operators können wir Daten einfach an die Konsole ausgeben.  -Objekts und des ostream , das zur Ausgabe von Daten an das Standardausgabegerät verwendet wird. Durch die Verwendung des cout<<

 Implementieren Sie nun die <<-Überladung in der Klasse:

	void operator<<(ostream& out)
	{
		out << _year << "年" << _month << "月" << _day << "日" << endl;
	}

ostream& ist ein Referenztyp, der einen Verweis auf das Ausgabestreamobjekt darstellt. Mithilfe des Referenztyps ostream& kann das Ausgabestreamobjekt an die Operatorüberladung übergeben werden.

 Wenn wir die Operatorüberladung << verwenden möchten, müssen wir das folgende Formular verwenden:

d1 << cout;//或者d1.operator<<(cout);

Der erste Parameter der Operatorüberladung << ist der linke Operand und der zweite Parameter ist der rechte Operand.

Obwohl dieses Formular die gewünschten Ergebnisse ausgeben kann, unterscheidet es sich von der herkömmlichen Methode, die wir cout<<d1 verwenden.

Wir können es ändern und den <<-Operator als globale Funktion überladen, indem wir als ersten Parameter einen Verweis auf das Ausgabestream-Objekt und als zweiten Parameter einen Verweis auf das Datumsklassenobjekt verwenden.

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

Gleichzeitig können Sie eine Friend-Funktionsdeklaration in der Datumsklasse erstellen, um der globalen <<-Operatorüberladung den Zugriff auf die privaten Mitgliedsvariablen des Datumsklassenobjekts d zu ermöglichen, sodass Sie auf die Mitglieder von zugreifen können das Objekt.

friend void operator<<(ostream& out, const Date& d);

Lass es uns testen: 

class Date
{
	friend void operator<<(ostream& out, const Date& d);
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout<< _year << "年" << _month << "月" << _day << "日" << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
void operator<<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
}

void Test()
{
	Date a(2023, 11, 24);
	a.Print();
	cout << a;
}

int main()
{
	Test();
	return 0;
}

 Die Überladung des Operators << wurde erfolgreich implementiert.

 

2. Kontinuierliche Ausgabe realisieren

Was ist, wenn es sich um die folgende kontinuierliche Ausgabe handelt?

void Test2()
{
	Date a(2023, 11, 24);
	Date b(2023, 11, 25);
	cout << a << b << endl;
}

Zu diesem Zeitpunkt meldet der Compiler einen Fehler.​ 

 

 Um die Form der kontinuierlichen Ausgabe zu unterstützen, müssen wir der <<-Überladung einen Rückgabewert hinzufügen.

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

Gleichzeitig muss auch die Deklaration der Friend-Funktion geändert werden:

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

 Mach mal einen Test:

class Date
{
	friend ostream& operator<<(ostream& out, const Date& d);
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout<< _year << "年" << _month << "月" << _day << "日" << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	return out;
}
void Test2()
{
	Date a(2023, 11, 24);
	Date b(2023, 11, 25);
	cout << a << b << endl;
}
int main()
{
	Test2();
	return 0;
}

Kontinuierliche Leistung erfolgreich erreicht: 

2. Stream-Eingabe

iostream, istream und cin sind verwandte Klassen und Objekte, die für die Eingabe in C++ verwendet werden.

  • iostream ist eine Header-Datei in der C++-Standardbibliothek, die die Definition von Stream-Klassen für die Eingabe und Ausgabe enthält. In der Header-Datei iostream sind die beiden Basisklassen istream und ostream definiert, die jeweils für Eingabe- und Ausgabeoperationen verwendet werden.

  • istream ist eine in der Headerdatei iostream definierte Klasse, die die Basisklasse des Eingabestreams darstellt. Die Klasse istream stellt grundlegende Funktionen und Schnittstellen für Eingabeoperationen bereit. Beispielsweise wird der Operator >> zum Lesen von Daten aus dem Stream verwendet.

  • cin ist ein Objekt der Klasse istream , bei der es sich um das Standard-Eingabestreamobjekt handelt. cin -Objekte können mithilfe des >> -Operators Daten vom Standardeingabegerät (normalerweise der Tastatur) lesen.

Zusammenfassung: iostream ist eine Header-Datei, istream ist die in iostream definierte Eingabestream-Basisklasse und < /span>  -Operators können wir Daten einfach über die Tastatur eingeben.  -Objekts und des  und wird zum Lesen von Daten vom Standardeingabegerät verwendet. Durch die Verwendung des cin ist ein Objekt der Klasse istreamcin>>

 Als Nächstes implementieren wir die Stream-Extraktion>>-Operatorüberladung, die mit der Stream-Einfügung<<-Implementierung identisch ist.

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

 einen Test machen

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

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

	void Print()
	{
		cout<< _year << "年" << _month << "月" << _day << "日" << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	return in;
}
void Test3()
{
	Date d;
	cin >> d;
	cout << d;
}
int main()
{
	Test3();
	return 0;
}

Überladung des Stream-Extraktionsoperators erfolgreich implementiert.​ 

Zusammenfassen:

Wenn die Deklaration und Definition einer Klasse in Dateien unterteilt ist, fügen wir die Überladungen der Stream-Extraktions- und Stream-Einfügungsoperatoren normalerweise als Inline-Funktionen in die Header-Datei ein, wodurch der Verknüpfungsprozess entfällt und der Aufruf der Adresse während des Kompilierungsprozesses ermöglicht wird.

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

inline istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	return in;
}
  • Wenn in C++ eine Memberfunktion direkt innerhalb einer Klasse definiert wird, wird sie als Inline-Funktion betrachtet. Die Definition und Deklaration von Inline-Funktionen erfolgt in der Klassendefinition, sodass der Compiler den Code der Funktion an der aufrufenden Stelle einfügen kann, anstatt ihn über einen Funktionsaufruf auszuführen.
  • Normalerweise eignen sich kurze Funktionen als Inline-Funktionen, da die Kosten für den Aufruf von Inline-Funktionen geringer sind und der zusätzliche Overhead von Funktionsaufrufen vermieden werden kann. Durch die Definition einer solchen Funktion innerhalb einer Klasse können Deklaration und Definition bequem zusammengefügt werden, wodurch die Lesbarkeit und Wartbarkeit des Codes verbessert wird.
  • Es ist jedoch zu beachten, dass es letztendlich die Entscheidung des Compilers ist, ob eine innerhalb einer Klasse definierte Memberfunktion als Inline-Funktion behandelt wird. Der Compiler kann anhand von Faktoren wie Komplexität, Aufrufhäufigkeit usw. entscheiden, ob eine Funktion inline erweitert werden soll.
  • Kurz gesagt, innerhalb einer Klasse definierte Kurzfunktionen können als Inline-Funktionen betrachtet werden, die die Ausführungseffizienz und Lesbarkeit des Codes verbessern können. Letztendlich liegt es jedoch am Compiler, zu entscheiden, ob eine Inline-Erweiterung durchgeführt wird.

3. const-Änderung

Die const-modifizierte „Member-Funktion“ wird als const-Member-Funktion bezeichnet. Die const-modifizierte Klassen-Member-Funktion ändert tatsächlich den in der Member-Funktion impliziten This-Zeiger, was darauf hinweist, dass kein Mitglied der Klasse in der Member-Funktion geändert werden kann.

Schauen wir uns den folgenden Code an:

class A {
public:
	void Print() 
    {
		cout << _a << endl;
	}
private:
	int _a = 1;
};
int main()
{
	A aa;
	aa.Print();
	return 0;
}

Erfolgreiche Ausgabe: 

Ist es in Ordnung, wenn aa mit const geändert wird?​ 

const A aa;

Das Programm meldet nach der Kompilierung einen Fehler: 

 

Dies ist auf das Problem der Erlaubnisverstärkung zurückzuführen.

 Der Parameter der Print-Funktion ist A*this und der Typ von aa ist const A*. Der Aufruf der Print-Funktion durch aa führt also zu einer Berechtigungsverstärkung. Wenn die Berechtigungen übersetzt werden, wird sie mit const vor dem this-Zeiger geändert . Dies ist ebenfalls verboten. Wir können den this-Zeiger nicht ändern. .

Diesmal gibt es eine neue indirekte Methode:

  • Die Grammatik legt fest, dass es sich um eine const-Mitgliedsfunktion handelt, und const ändert *this, was bedeutet, dass der Typ davon zum const A*-Typ wird.
  • Wenn eine Mitgliedsfunktion die Mitgliedsvariable nicht intern ändert, fügen Sie am besten const hinzu. Es können sowohl const-Objekte als auch gewöhnliche Objekte aufgerufen werden.

 Zu diesem Zeitpunkt können wir die Implementierung vonC++-Klassen und -Objekten (4)-Date-Klasse in der Date.h-Datei davon implementieren Artikel Einige Mitgliedsfunktionen wurden mit const geändert.

#include <iostream>
#include <assert.h>
using namespace std;

class Date {
public:
	Date(int year = 0, int month = 0, int day = 0);
	void Print();
	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);

	// d1 - 100
	Date operator-(int day);

	// d1 - d2;
	int operator-(const Date& d) const;

	// ++d1
	Date& operator++();

	// d1++
	Date operator++(int);
	
	Date& operator--();

	Date operator--(int);

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

4. Holen Sie sich die Adresse

.Get-Adresse und const-Get-Address-Operator überladen

Diese beiden Standard-Memberfunktionen müssen im Allgemeinen nicht neu definiert werden und werden vom Compiler standardmäßig generiert.

class Date
{
public :
    Date* operator&()
    {
        return this ; 
    }
    const Date* operator&()const
    {
        return this ;
    }
private :
    int _year ; // 年
    int _month ; // 月
    int _day ; // 日
};
Diese beiden Operatoren müssen im Allgemeinen nicht überladen werden. Verwenden Sie einfach die vom Compiler generierte Standardüberladung zur Adressübernahme. Nur unter besonderen Umständen ist dies erforderlich.
Zum Beispiel zum Überladen möchte, dass andere den angegebenen Inhalt erhalten.

5. [ ] Operatorüberlastung

class Array
{
public:
	int& operator[](int i)
	{
		assert(i < 10);

		return _a[i];
	}

	const int& operator[](int i) const
	{
		assert(i < 10);

		return _a[i];
	}
private:
	int _a[10];
	int _size;
};

void Func(const Array& aa)
{
	for (int i = 0; i < 10; ++i)
	{
		//aa[i]++;
		cout << aa[i] << " ";
	}
}

Schauen wir uns zunächst dieArrayKlassen an:

  • ArrayDie Klasse definiert ein privates Integer-Array_a mit einer Größe von 10 und eine private Integer-Variable_size.

  • ArrayDie Klasse überlädt den Operator [], sodass wir Objekte der Klasse Array wie gewöhnliche Arrays verwenden können.

  • operator[]Es gibt zwei Versionen der Funktion, eine ist die nicht konstante Version und die andere ist die konstante Version. Die nicht konstante Version gibt eine änderbare Referenz zurück, und die konstante Version gibt eine nicht änderbare konstante Referenz zurück.

  • In der Funktion operator[] wird die Funktion assert verwendet, um sicherzustellen, dass der Index i weniger als 10 to beträgt Verhindern Sie, dass das Array den zulässigen Bereich überschreitet.

Dann schauen wir uns die Func-Funktion an:

  • FuncDie Funktion akzeptiert eine konstante Referenz der Klasse Array als Parameter. Da Parameter konstante Referenzen sind, können wir den Wert des Parameters in der Funktion nicht ändern.

  • In der FunktionFunc gibt es eine Schleife und die Schleifenvariablei durchläuft den Wert 0 bis 9. Im Schleifenkörper wird aa[i]++ zunächst auskommentiert. Dies liegt daran, dass aa eine konstante Referenz ist und wir ihren Wert nicht ändern können. Verwenden Sie dann cout, um den Wert von aa[i] auszudrucken, und drucken Sie dann ein Leerzeichen.

Zum Beispiel, wenn wir ein Objekt der Klasse erstellen und das Array von 0 bis 9 initialisieren , und rufen Sie dann auf, dann wird auf der Konsole ausgegeben. Arraya_aFunc(a)0 1 2 3 4 5 6 7 8 9

Supongo que te gusta

Origin blog.csdn.net/m0_73800602/article/details/134588898
Recomendado
Clasificación