c++详细讲解构造函数的拷贝流程
什么是构造函数
在C++中,构造函数是一种特殊的成员函数,用于创建和初始化对象。当一个对象被创建时,构造函数会自动调用,完成对象的初始化工作。
构造函数的拷贝流程
当需要创建一个新对象并将其初始化为另一个对象的副本时,就需要使用到拷贝构造函数。拷贝构造函数用于实现一个对象复制另一个对象的所有成员变量的功能。
在C++中,每个类都有一个默认的拷贝构造函数,它会按照成员变量的顺序逐个复制。以下是一个简单的示例:
class Person {
public:
int age;
std::string name;
};
int main() {
Person p1;
p1.age = 20;
p1.name = "Tom";
Person p2 = p1; // 使用拷贝构造函数将p1复制给p2
std::cout << "p1's age is " << p1.age << ", name is " << p1.name << std::endl;
std::cout << "p2's age is " << p2.age << ", name is " << p2.name << std::endl;
return 0;
}
输出结果为:
p1's age is 20, name is Tom
p2's age is 20, name is Tom
可以看到,p1和p2的成员变量都被正确地复制过来了。拷贝构造函数会在创建新对象时调用,并将原对象的值拷贝到新对象上。
浅拷贝
以上示例中的拷贝构造函数实现的是浅拷贝。浅拷贝只是将原对象的成员变量的值复制过来,并没有创建新的对象,也没有为成员变量分配新的内存空间。这种方式的缺点是,如果原对象和副本对象指向同一块内存时,会导致副本对象发生意外修改,原对象的值也会被改变。
以下是一个示例:
class Person {
public:
int age;
std::string* name;
Person(int age, std::string* name) {
this->age = age;
this->name = name;
}
};
int main() {
std::string name = "Tom";
Person p1(20, &name);
Person p2 = p1; // 使用拷贝构造函数将p1复制给p2
std::cout << "p1's name is " << *(p1.name) << std::endl;
std::cout << "p2's name is " << *(p2.name) << std::endl;
*(p2.name) = "Jerry"; // 修改p2的name
std::cout << "After modification:" << std::endl;
std::cout << "p1's name is " << *(p1.name) << std::endl;
std::cout << "p2's name is " << *(p2.name) << std::endl;
return 0;
}
输出结果为:
p1's name is Tom
p2's name is Tom
After modification:
p1's name is Jerry
p2's name is Jerry
可以看到,修改了p2的成员变量name
,同时也修改了p1的成员变量name
。这是因为p1和p2的成员变量name
指向同一块内存空间,造成了意外修改。
深拷贝
为了规避上述的问题,需要使用到深拷贝。深拷贝会为新对象重新分配内存空间,并将原对象的值复制到新的内存空间中,从而避免了意外修改。
以下是一个示例:
class Person {
public:
int age;
std::string* name;
Person(int age, std::string* name) {
this->age = age;
this->name = new std::string(*name); // 新分配内存空间,拷贝name指向的字符串
}
~Person() {
delete name; // 在析构函数中释放内存空间
}
Person(const Person& p) { // 拷贝构造函数
this->age = p.age;
this->name = new std::string(*(p.name)); // 深拷贝
}
};
int main() {
std::string name = "Tom";
Person p1(20, &name);
Person p2 = p1; // 使用拷贝构造函数将p1复制给p2
std::cout << "p1's name is " << *(p1.name) << std::endl;
std::cout << "p2's name is " << *(p2.name) << std::endl;
*(p2.name) = "Jerry"; // 修改p2的name
std::cout << "After modification:" << std::endl;
std::cout << "p1's name is " << *(p1.name) << std::endl;
std::cout << "p2's name is " << *(p2.name) << std::endl;
return 0;
}
输出结果为:
p1's name is Tom
p2's name is Tom
After modification:
p1's name is Tom
p2's name is Jerry
可以看到,修改了p2的成员变量name
后,p1的成员变量name
并没有发生改变。这是因为p1和p2的成员变量name
指向不同的内存空间,使用深拷贝避免了意外修改。同时,在析构函数中释放了拷贝出来的内存空间。
结论
构造函数、拷贝构造函数是自定义类中必须要定义的两个函数。拷贝构造函数会在创建新对象时调用,并将原对象的值拷贝到新对象上,在使用时需要注意浅拷贝和深拷贝的区别。如果对象中存在指针类型成员变量,则必须使用深拷贝避免数据异常。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:c++详细讲解构造函数的拷贝流程 - Python技术站