以下是深入C++中构造函数、拷贝构造函数、赋值操作符、析构函数的调用过程总结:
构造函数的调用过程
- 当一个对象被创建的时候,其构造函数会被自动调用;
- 如果该类没有定义构造函数,则系统会为该类自动生成一个默认构造函数;
- 如果该类存在构造函数,则必须在用户的代码中显式地调用构造函数;
- 如果一个类有多个构造函数,则在创建对象时可以根据需要选择其中之一来使用;
- 构造函数调用顺序为:基类先于派生类,而成员对象的初始化顺序则是它们在类定义中出现的顺序。
#include <iostream>
using namespace std;
class Person {
public:
Person() {
cout << "调用了默认构造函数" << endl;
}
Person(int age) {
cout << "调用了带参数的构造函数" << endl;
}
};
int main() {
Person p1; // 调用默认构造函数,输出:调用了默认构造函数
Person p2(20); // 调用带参数的构造函数,输出:调用了带参数的构造函数
return 0;
}
拷贝构造函数的调用过程
- 当使用一个已经存在的对象去初始化同类对象时,将会调用拷贝构造函数。对象可以直接作为参数传递给函数或从函数中返回时,也会调用拷贝构造函数;
- 如果该类没有定义拷贝构造函数,则系统会为该类自动生成一个默认拷贝构造函数;
- 自定义的拷贝构造函数需要将传入的对象的属性值复制到新创建的对象中;
- 如果一个类有多个构造函数,则在创建对象时可以根据需要选择其中之一来使用。
#include<iostream>
using namespace std;
class Person {
public:
int age;
char *name;
Person() : age(0), name(NULL) {
cout << "默认构造函数被调用" << endl;
}
Person(int age_, char *name_) : age(age_), name(name_) {
cout << "带参数的构造函数被调用" << endl;
}
Person(const Person &p) {
cout << "拷贝构造函数被调用" << endl;
this->age = p.age;
// 复制字符串时需要开辟新的存储空间,保证不会影响原对象
if (p.name != NULL) {
this->name = new char[strlen(p.name) + 1];
strcpy(this->name, p.name);
}
}
~Person() {
cout << "析构函数被调用" << endl;
if (name != NULL) { delete[]name; }
}
};
void print(const Person& p) {
cout << "Person age: " << p.age << ", name: " << p.name << endl;
}
int main() {
Person p1(20, "Tom"); // 调用带参数构造函数
print(p1);
Person p2(p1); // 调用拷贝构造函数
print(p2);
return 0;
}
赋值操作符的调用过程
- 当用一个对象去初始化另一个同类对象时会调用拷贝构造函数,但是当对象之间发生赋值操作时,则会调用赋值操作符;
- 如果该类没有定义赋值操作符,则系统会为该类自动生成一个默认赋值操作符;
- 自定义的赋值操作符需要将传入的对象的属性值复制到当前对象中,同时防止出现自赋值的情况,即判断传入的对象是否是当前对象。
#include<iostream>
using namespace std;
class Person {
public:
int age;
char *name;
Person() : age(0), name(NULL) {
cout << "默认构造函数被调用" << endl;
}
Person(int age_, char *name_) : age(age_), name(name_) {
cout << "带参数的构造函数被调用" << endl;
}
Person(const Person &p) {
cout << "拷贝构造函数被调用" << endl;
this->age = p.age;
// 复制字符串时需要开辟新的存储空间,保证不会影响原对象
if (p.name != NULL) {
this->name = new char[strlen(p.name) + 1];
strcpy(this->name, p.name);
}
}
~Person() {
cout << "析构函数被调用" << endl;
if (name != NULL) { delete[]name; }
}
Person operator=(const Person &p) {
cout << "赋值操作符被调用" << endl;
if (this == &p) { // 自赋值的判断
return *this;
}
this->age = p.age;
if (this->name != NULL) { delete[]name; } // 先删除当前对象中已有的字符串变量
if (p.name != NULL) { // 复制字符串并开辟新的存储空间
this->name = new char[strlen(p.name) + 1];
strcpy(this->name, p.name);
}
return *this;
}
};
void print(const Person& p) {
cout << "Person age: " << p.age << ", name: " << p.name << endl;
}
int main() {
Person p1(20, "Tom"); // 调用带参数构造函数
print(p1);
Person p2; // 调用默认构造函数
p2 = p1; // 调用赋值操作符函数
print(p2);
return 0;
}
析构函数的调用过程
- 对象在销毁时,系统会自动调用其析构函数;
- 当对象为局部自动对象时,程序在此对象的作用域结束时会自动调用其析构函数;
- 如果该类没有定义析构函数,则系统会为该类自动生成一个默认析构函数;
- 自定义的析构函数需要释放对象在创建过程中所占用的动态分配的内存空间。
#include<iostream>
using namespace std;
class Person {
public:
Person() {
cout << "默认构造函数被调用" << endl;
}
~Person() {
cout << "析构函数被调用" << endl;
}
};
int main() {
Person p; // 调用默认构造函数
return 0; // 调用析构函数
}
以上就是深入C++中构造函数、拷贝构造函数、赋值操作符、析构函数的调用过程总结的攻略,我们可以看到,构造函数,拷贝构造函数,赋值操作符以及析构函数都是类的重要组成部分,它们的正确使用对于保证程序的稳定性非常重要。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:深入C++中构造函数、拷贝构造函数、赋值操作符、析构函数的调用过程总结 - Python技术站