Detaillierte Erläuterung des C++-Konstruktors und -Destruktors

Überblick

In C++ werden Konstruktoren und Destruktoren zum Initialisieren und Bereinigen von Objekten verwendet, und diese beiden Funktionen werden vom Compiler automatisch aufgerufen. Objektinitialisierung und -bereinigung sind sehr wichtig. Wenn wir keinen Konstruktor und Destruktor bereitstellen, stellt der Compiler automatisch eine leere Implementierung der beiden Funktionen bereit.

Konstruktor: Wird hauptsächlich verwendet, um den Eigenschaften von Objektmitgliedern beim Erstellen von Funktionen Werte zuzuweisen.
Destruktor: Wird hauptsächlich verwendet, um einige Reinigungsarbeiten durchzuführen (z. B. das Freigeben des von new im Heap-Bereich geöffneten Speicherplatzes), bevor das Objekt zerstört wird.

Hauptmerkmale:
Konstruktorsyntax: Klassenname (){}
1. Konstruktor, kein Rückgabewert und keine Lücke
2. Der Funktionsname ist derselbe wie der Klassenname
3. Der Konstruktor kann Parameter haben, daher kann es zu Überladungen kommen
4. Das Programm ist in Beim Aufrufen des Objekts wird der Konstruktor automatisch aufgerufen, es ist kein manueller Aufruf erforderlich und er wird nur einmal aufgerufen

Syntax des Destruktors: ~Klassenname(){}
1. Destruktor, kein Rückgabewert und keine Lücke
2. Der Funktionsname ist derselbe wie der Klassenname und vor dem Namen wird ein Symbol hinzugefügt~
3. Der Destruktor kann keine Parameter haben. Daher kann es nicht zu einer Überladung kommen.
4. Das Programm ruft den Destruktor automatisch auf, bevor das Objekt zerstört wird. Es ist nicht erforderlich, ihn manuell aufzurufen, und er wird nur einmal aufgerufen

Andere Eigenschaften:

  • Konstruktor und Destruktor sind spezielle öffentliche Mitgliedsfunktionen. Jede Klasse verfügt über einen Standardkonstruktor und -destruktor.
  • Der Konstruktor wird vom System automatisch aufgerufen, wenn die Klasse definiert wird, und der Destruktor wird vom System automatisch aufgerufen, wenn die Klasse zerstört wird.
  • Der Name des Konstruktors ist derselbe wie der Name der Klasse . Eine Klasse kann mehrere Konstruktoren , aber nur einen Destruktor haben . Verschiedene Konstruktoren unterscheiden sich durch die Anzahl der Parameter und Parametertypen;
  • Wir können der Klasse im Konstruktor Ressourcen zuweisen und die entsprechenden Ressourcen im Destruktor der Klasse freigeben.
  • Wenn der Programmierer keine Konstruktion und Zerstörung bereitstellt, stellt das System standardmäßig eine leere Implementierung bereit
  • Konstruktoren und Destruktoren müssen öffentlich definiert werden, bevor sie aufgerufen werden können

Einfaches Beispiel:

#include<iostream>
using namespace std;
class Person
{
    
    
public:
	Person()
	{
    
    
		cout << "调用构造函数" << endl;
	}
	~Person()//对象销毁前,自动调用
	{
    
    
		cout << "析构函数的调用" << endl;
	}
};
void test()
{
    
    
	//创建对象
	Person  p;//这是一个局部变量,test执行完毕后会释放该对象 进而调用析构函数
}
int main()
{
    
    
	Person  p1;//如果在main函数创建对象,析构函数会在按任意键后再调用
	test();
	system("pause");
	return 0;
}

Laufergebnis:
Fügen Sie hier eine Bildbeschreibung ein
Sie können sehen, dass das Programm zuerst den Konstruktor von Objekt p1 aufruft und dann den Konstruktor und Destruktor von Objekt p aufruft. Nach dem Drücken einer beliebigen Taste sollte der Destruktor von p1 angezeigt werden, da p1 Teil der Hauptfunktion ist Die Variable wird freigegeben, wenn die Hauptfunktion beendet wird, und der Destruktor von p1 wird aufgerufen, wenn er freigegeben wird.

Klassifizierung von Konstrukteuren

Zwei Klassifizierungsmethoden:

  • Geteilt durch Parameter: parametrisierte Konstruktion und nichtparametrische Konstruktion

  • Unterteilt nach Typ: Normalbau und Kopierbau

Drei Aufrufmethoden:

  • Klammern (am häufigsten)

  • explizite Methode

  • implizite Konvertierungsmethode

Für die drei Konstruktoren mit Parametern, ohne Parameter und Kopieren gibt es drei Beispiele für aufrufende Methoden (es gibt nur eine aufrufende Methode ohne Parameter):

#include<iostream>
using namespace std;
class Person
{
    
    
public:
	Person()
	{
    
    
		cout << "调用无参(默认)构造函数" << endl;
	}
	Person(int a)
	{
    
    
		age = a;
		cout << "调用有参构造函数" << endl;
	}
	//拷贝构造函数用于拷贝传入的类到自身类上 
	//除了拷贝构造函数外都是普通构造函数
	Person(const Person &p)//传入的类不希望被改变所以加const 传入引用用p指向该类
	{
    
    
		age = p.age;
		cout << "调用拷贝构造函数" << endl;
	}
	~Person()
	{
    
    
		cout << "析构函数的调用" << endl;
	}
	int age;

};
void test()
{
    
    
    //调用
    //1.括号法
	//注意:调用无参构造时不要输入()
	//Person p();会被编译器认为是函数的声明
	Person p;//调用无参构造函数
	Person p1(10);//调用有参函数构造
	Person p2(p1);//调用拷贝构造函数
	cout <<"p1的年龄"<< p1.age << endl;
	cout <<"p2的年龄"<< p2.age << endl;
	
	//2.显式法
	Person p3;//调用无参构造函数
	Person p4=Person (10);//调用有参函数构造
	Person p5=Person (p1);//调用拷贝构造函数
	//Person(10)为匿名对象 等号左侧就是它的名 
	//特点:当前行结束时,系统会立即回收掉匿名对象 即它的析构函数会在该行结束后就调用而不是test函数结束
	
	//3.隐式转换法
	Person p6 = 10; //调用有参函数构造 相当于Person p6=Person(10);  假如有两个参数就是 Person p6 = (10,9);
	Person p7 = p1;//调用拷贝构造函数 相当于Person p7=Person(p1);
}
int main()
{
    
    
	test();
	system("pause");
	return 0;
}

1. Konstruktor ohne Argumente (Standard).

Ein Konstruktor ohne Parameter erstellt beispielsweise eine Person-Klasse, die zwei Attribute enthält: Alter und Größe, Alter (Ganzzahl), Höhe (Ganzzahlzeiger). Das Standardalter für die Konstruktionsinitialisierung ist 0 und die Höhe ist 0. Wenn der Benutzer es nicht implementiert, verwendet das System standardmäßig eine leere Implementierung.

#include<iostream>
using namespace std;
class Person
{
    
    
public:
	//默认构造函数
	Person();
	int m_Age;
	int* m_Height;
};
//初始化年龄和身高
Person::Person() 
{
    
    
	cout << "默认构造函数的调用!" << endl;
	this->m_Age = 0;
	this->m_Height = new int(0);
}
int main()
{
    
    
	Person p;
	cout << "此人的年龄是: " << p.m_Age << endl;
	cout << "此人的身高是: " << *(p.m_Height) << endl;
	return 0;
}

Beachten Sie, dass es sich beim Erstellen eines Objekts um Person p handelt. Wenn wir Person p () schreiben, geht der Compiler auf diese Weise davon aus, dass eine Funktion p erstellt wurde, der Rückgabewerttyp Person ist und der formale Parameter leer ist {} ist für die Implementierung leer, daher müssen Sie darauf achten.

Ergebnis:
Fügen Sie hier eine Bildbeschreibung ein

2. Konstruktor mit Parametern

Lassen Sie uns die parametrisierte Struktur einführen oder weiterhin das obige Beispiel verwenden, um hinzuzufügen. Wenn wir ein Objekt mit einem bestimmten Alter und einer bestimmten Höhe erstellen möchten, müssen wir die parametrisierte Struktur verwenden. Beispiel:

#include<iostream>
using namespace std;
class Person
{
    
    
public:
	//默认构造函数
	Person();
	//有参构造
	Person(int age, int height);
	int m_Age;
	int* m_Height;
};
//默认构造
Person::Person() 
{
    
    
	cout << "默认构造函数的调用!" << endl;
	this->m_Age = 0;
	this->m_Height = new int(0);
}
//有参构造,把age赋值给m_Age,身高用m_Height指向
Person::Person(int age,int height)
{
    
    
	cout << "有参构造函数的调用!" << endl;
	this->m_Age = age;
	this->m_Height = new int(height);
}
int main()
{
    
    
	Person p(18,175);
	cout << "此人的年龄是: " << p.m_Age << endl;
	cout << "此人的身高是: " << *(p.m_Height) << endl;
	return 0;
}

Fügen Sie hier eine Bildbeschreibung ein

3. Delegierender Konstruktor

Wie der Name schon sagt, soll der delegierte Konstruktor die von ihm selbst erstellten Dinge an andere Konstruktoren übergeben. Wenn ich beispielsweise den Standardkonstruktor ändere,

#include<iostream>
using namespace std;
class Person
{
    
    
public:
	//默认构造函数
	Person();
	//有参构造
	Person(int age, int height);
	//拷贝构造
	Person(const Person& p);
	int m_Age;
	int* m_Height;
};
//默认构造
Person::Person() :Person(0, 0)
{
    
    
	cout << "委托构造函数的调用!" << endl;
}
//有参构造,把age赋值给m_Age,身高用m_Height指向
Person::Person(int age, int height)
{
    
    
	cout << "有参构造函数的调用!" << endl;
	this->m_Age = age;
	this->m_Height = new int(height);
}
//拷贝构造函数调用
Person::Person(const Person& p)
{
    
    
	cout << "拷贝构造函数的调用!" << endl;
	this->m_Age = p.m_Age;
	this->m_Height = new int(*p.m_Height);
}
int main()
{
    
    
	Person p;
	cout << "p的年龄是: " << p.m_Age << endl;
	cout << "p的身高是: " << *(p.m_Height) << endl;
	return 0;
}

Fügen Sie hier eine Bildbeschreibung ein

4. Konstruktor kopieren (kopieren).

Das Obige besteht darin, den Wert des Attributs am Anfang zu initialisieren, und der Kopierkonstruktor besteht darin, am Anfang ein Objekt zu übergeben, die Attribute des Objekts in dieses Objekt zu kopieren und das Objekt zu initialisieren (die übergebenen Parameter können als a betrachtet werden). Schaf, nach der Kopierkonstruktion wird ein neues Schaf geklont, und die Attribute der beiden Schafe sind gleich.) Demnach kann die Erstellung des Objekts realisiert werden.

#include<iostream>
using namespace std;
class Person
{
    
    
public:
	//默认构造函数
	Person();
	//有参构造
	Person(int age, int height);
	//拷贝构造
	Person(const Person& p);
	int m_Age;
	int* m_Height;
};
//默认构造
Person::Person()
{
    
    
	cout << "默认构造函数的调用!" << endl;
	this->m_Age = 0;
	this->m_Height = new int(0);
}
//有参构造,把age赋值给m_Age,身高用m_Height指向
Person::Person(int age, int height)
{
    
    
	cout << "有参构造函数的调用!" << endl;
	this->m_Age = age;
	this->m_Height = new int(height);
}
//拷贝构造函数调用
Person::Person(const Person& p)
{
    
    
	cout << "拷贝构造函数的调用!" << endl;
	this->m_Age = p.m_Age;
	this->m_Height = new int(*p.m_Height);
}
int main()
{
    
    
	Person p1(18, 175);
	cout << "p1的年龄是: " << p1.m_Age << endl;
	cout << "p1的身高是: " << *(p1.m_Height) << endl;
	Person p2(p1);//将对象p1复制给p2。注意复制和赋值的概念不同 
	cout << "p2的年龄是: " << p2.m_Age << endl;
	cout << "p2的身高是: " << *(p2.m_Height) << endl;
	return 0;
}

Fügen Sie hier eine Bildbeschreibung ein

Der Kopierkonstruktor implementiert standardmäßig eine Wertkopie (flache Kopie). Hier verwende ich die Deep-Copy-Struktur, die verhindern kann, dass der Speicher im Heap-Bereich wiederholt vom Destruktor freigegeben wird, und die Sicherheit des Codes gewährleistet. Ich werde die tiefen und flachen Kopien neu organisieren, wenn ich Zeit habe. Das Hinzufügen von Konstanteneinschränkungen vor der Kopie kann die Änderung von Mitgliedsattributen verhindern und vollständige Konsistenz gewährleisten. Dabei wird eine L-Wert-Referenz zum Ausführen einer Zuweisung verwendet. Das Obige ist eine Referenzkopie des L-Wert-Parameters.

【denken】
Ist es in Ordnung, die Parameter des Konstruktors ohne const zu kopieren (kopieren)? Welche Rolle spielt const
? Am besten fügen Sie const hinzu. Konstante L-Wert-Referenzen können L-Werte, R-Werte, konstante L-Werte und konstante R-Werte akzeptieren, während L-Wert-Referenzen nur L-Werte akzeptieren können.
Wenn ein temporäres Objekt kopiert werden muss, z. B. Integer a(Integer(100)); meldet der Kopierkonstruktor ohne const einen Fehler.

Weitere Informationen finden Sie unter https://blog.csdn.net/jiaojinlin/article/details/124744513

5. Konstruktor verschieben

Die Einführung dieses Teils ist nicht klein. Bitte wechseln Sie zu einem anderen Artikel für eine detaillierte Einführung: Detaillierte Erläuterung des C++-Verschiebungskonstruktors

Regeln für Konstruktoraufrufe

Standardmäßig fügt der C++-Compiler einer Klasse mindestens drei Funktionen hinzu

1. Standardkonstruktor (keine Parameter, Funktionskörper ist leer)

2. Standarddestruktor (keine Parameter, Funktionskörper ist leer)

3. Der Standardkopierkonstruktor, der den Wert der Eigenschaft kopiert

Die Regeln für den Konstruktoraufruf lauten wie folgt:

Wenn der Benutzer einen Konstruktor mit Parametern definiert, stellt C++ keine standardmäßige Konstruktion ohne Argumente mehr bereit, sondern eine standardmäßige Kopierkonstruktion

Wenn der Benutzer einen Kopierkonstruktor definiert, stellt C++ keine anderen Konstruktoren mehr bereit

#include<iostream>
using namespace std;
class Person {
    
    
public:
	//无参(默认)构造函数
	Person() 
	{
    
    
		cout << "无参构造函数!" << endl;
	}
	//有参构造函数
	Person(int a)
	{
    
    
		age = a;
		cout << "有参构造函数!" << endl;
	}
	//拷贝构造函数
	Person(const Person& p) 
	{
    
    
		age = p.age;
		cout << "拷贝构造函数!" << endl;
	}
	//析构函数
	~Person() 
	{
    
    
		cout << "析构函数!" << endl;
	}
public:
	int age;
};

void test01()
{
    
    
	Person p1(18);
	//如果不写拷贝构造,编译器会自动添加拷贝构造,并且做浅拷贝操作
	Person p2(p1);

	cout << "p2的年龄为: " << p2.age << endl;
}

void test02()
{
    
    
	//如果用户提供有参构造,编译器不会提供默认构造,会提供拷贝构造
	Person p1; //此时如果用户自己没有提供默认构造,会出错
	Person p2(10); //用户提供的有参
	Person p3(p2); //此时如果用户没有提供拷贝构造,编译器会提供

	//如果用户提供拷贝构造,编译器不会提供其他构造函数
	Person p4; //此时如果用户自己没有提供默认构造,会出错
	Person p5(10); //此时如果用户自己没有提供有参,会出错
	Person p6(p5); //用户自己提供拷贝构造
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Zerstörer

Der Destruktor wird verwendet, um das Objekt zu bereinigen, bevor es gelöscht wird, und wird automatisch aufgerufen, wenn der Lebenszyklus des Objekts bald zu Ende geht. (Der Destruktor kann das Objekt bereinigen und den Speicher freigeben.)
Der Destruktor ~加上类名() arbeitet und hat den Zweck, die Daten zu löschen und den Speicher freizugeben.
Hier ist ein Beispiel: Erstellen Sie einen Standardkonstruktor p, führen Sie eine Standardkonstruktion durch, rufen Sie dann die Anzeigeinformationsfunktion auf, um Informationen auszugeben, und zerstören Sie schließlich die Funktion, um den Inhalt freizugeben und Speicherverluste zu verhindern!

#include<iostream>
using namespace std;
class Person
{
    
    
public:
	//默认构造函数
	Person();
	//有参构造
	Person(int age, int height);
	//拷贝构造
	Person(const Person& p);
	//移动构造函数
	Person(Person&& p);
	//析构函数
	~Person();
	//展示信息
	void ShowPerson();
	int m_Age;
	int* m_Height;
};
//默认构造
Person::Person()
{
    
    
	cout << "默认构造函数的调用!" << endl;
	this->m_Age = 0;
	this->m_Height = new int(0);
}
//有参构造,把age赋值给m_Age,身高用m_Height指向
Person::Person(int age, int height)
{
    
    
	cout << "有参构造函数的调用!" << endl;
	this->m_Age = age;
	this->m_Height = new int(height);
}
//拷贝构造函数调用
Person::Person(const Person& p):m_Age(p.m_Age),m_Height(new int (*p.m_Height))
{
    
    
	cout << "拷贝构造函数的调用!" << endl;
	/*this->m_Age = p.m_Age;
	this->m_Height = new int(*p.m_Height);*/
}
//移动构造函数
Person::Person(Person&& p)
{
    
    
	cout << "移动构造函数的调用!" << endl;
	this->m_Age = p.m_Age;
	this->m_Height = p.m_Height;
	p.m_Height = NULL;
}
//展示信息
void Person::ShowPerson()
{
    
    
	cout << "年龄是: " << this->m_Age << endl;
    cout << "身高是: " << *(this->m_Height) << endl;
}
Person::~Person()
{
    
    
	cout << "析构函数的调用!" << endl;
	if (this->m_Height != NULL)
	{
    
    
		delete this->m_Height;
	}	
}
//返回一个右值的对象
Person GetPerson()
{
    
    
	Person p;
	return p;
}
int main()
{
    
    
	Person p;
	p.ShowPerson();
	return 0;
}

Fügen Sie hier eine Bildbeschreibung ein

https://blog.csdn.net/qq_44768163/article/details/114661958
https://blog.csdn.net/hbbfvv1h/article/details/115371496
https://blog.csdn.net/m0_61973596/ _ Artikel/Details/123458069【优质】
https://blog.csdn.net/qqyuanhao163/article/details/101396233
https://blog.csdn.net/weixin_39270987/article/details/116306065

https://blog.csdn.net/zyq11223/article/details/48766515#
https://blog.csdn.net/u014201706/article/details/103032246
https://blog.csdn.net/qq_34170700/article/details /107214554
https://blog.csdn.net/yi_chengyu/article/details/120775215

Supongo que te gusta

Origin blog.csdn.net/weixin_44788542/article/details/126187645
Recomendado
Clasificación