C++拷贝构造函数
C++中的拷贝构造函数是一种特殊的构造函数,它用于创建一个新的对象,该对象是通过复制另一个对象的值而创建的。拷贝构造函数通常被用于参数传递和返回值传递中,以及通过值传递或者显式调用来创建副本。
拷贝构造函数的语法形式如下:
class MyClass {
public:
MyClass(const MyClass& other) { // 拷贝构造函数
// 执行拷贝操作
}
};
拷贝构造函数的参数是一个常量引用,它表示要被复制的对象。在拷贝构造函数的执行过程中,我们需要创建一个新的对象,并把所有数据成员的值复制到新的对象中。
通常情况下,拷贝构造函数的实现方式如下所示:
class MyClass {
public:
MyClass(const MyClass& other) { // 拷贝构造函数
mData = other.mData; // 复制数据成员的值
}
private:
int mData;
};
但是,如果对象含有动态分配的内存,我们通常需要在拷贝构造函数中进行深拷贝,以确保新对象和原对象之间有独立的内存空间。
下面是一个示例,展示了拷贝构造函数的使用:
#include <iostream>
using namespace std;
class MyInt {
public:
MyInt(int val) : mData(new int(val)) {}
~MyInt() { delete mData; }
MyInt(const MyInt& other) : mData(new int(*other.mData)) {} // 拷贝构造函数
int getVal() const { return *mData; }
private:
int *mData;
};
int main() {
MyInt a(10);
MyInt b = a; // 调用拷贝构造函数
cout << "a: " << a.getVal() << endl;
cout << "b: " << b.getVal() << endl;
return 0;
}
在这个例子中,我们定义了一个简单的类MyInt
,该类包含一个指向int
型数据的指针。在构造函数中,我们使用new
创建了一个动态分配的内存空间。在拷贝构造函数中,我们需要使用另一个对象的值创建一个新的对象,这里使用了深拷贝的方式。
然后,我们创建了一个类MyInt
的对象a
,并将它的值设置为10。接着,我们将对象a
的值复制给了对象b
,这里会调用拷贝构造函数。最后,我们打印了对象a
和对象b
的值,可以看到它们的值是相同的。
C++拷贝构造函数会被隐式创建吗
如果你没有显式地定义拷贝构造函数,在需要使用拷贝构造函数的情况下,编译器会自动隐式地创建拷贝构造函数。隐式定义的拷贝构造函数将会使用其它已存在的构造函数,以深复制的方式来创建新的对象。它的语法如下:
class MyClass {
public:
MyClass(const MyClass& other) { // 隐式拷贝构造函数
// 执行深拷贝操作
}
};
需要注意的是,如果你已经显式定义了拷贝构造函数,那么编译器就不会再隐式定义一个拷贝构造函数了。
下面是一个例子,展示了当你没有显式定义拷贝构造函数时,编译器会自动隐式创建拷贝构造函数:
#include <iostream>
#include <string>
using namespace std;
class MyClass {
public:
MyClass(string name) : mName(name) {}
string getName() const { return mName; }
private:
string mName;
};
int main() {
MyClass obj1("Alice");
MyClass obj2 = obj1; // 调用隐式拷贝构造函数
cout << "obj1: " << obj1.getName() << endl;
cout << "obj2: " << obj2.getName() << endl;
return 0;
}
在这个例子中,我们定义了一个简单的类MyClass
,该类包含一个名字成员变量mName
。在构造函数中,我们使用给定的名字初始化mName
。在main()
函数中,我们创建了一个类MyClass
的对象obj1
,并将其名字设置为"Alice"。接着,我们将对象obj1
的值复制给了对象obj2
。由于我们没有显式定义拷贝构造函数,因此编译器将自动隐式地创建一个拷贝构造函数。最后,我们打印了对象obj1
和对象obj2
的名字,可以看到它们的名字是相同的。
有默认拷贝构造函数为什么还要显示创建拷贝构造函数
即便C++提供默认的拷贝构造函数,但是在一些情况下,我们需要自己显示地定义拷贝构造函数。以下是一些需要显示定义拷贝构造函数的情况:
- 类中包含指针成员时,需要进行深拷贝,否则会出现浅拷贝的问题。例如:
class Person {
public:
char* name;
int age;
Person(const char* n, int a) {
name = new char[strlen(n) + 1];
strcpy(name, n);
age = a;
}
// 拷贝构造函数
Person(const Person& p) {
name = new char[strlen(p.name) + 1];
strcpy(name, p.name);
age = p.age;
}
// 析构函数
~Person() {
delete[] name;
}
};
-
类中包含文件指针时,需要在拷贝构造函数中打开一个新的文件指针,并复制原来指向的文件内容。
-
禁止浅拷贝。
-
调用基类的拷贝构造函数。我们可以在派生类的拷贝构造函数中调用基类的拷贝构造函数。
总之,需要显示定义拷贝构造函数的情况多种多样,需要根据具体情况来决定是否需要定义。
C++深浅拷贝区别
在C++中,拷贝是一个经常遇到的操作。有时候我们需要创建一个与原始对象一模一样的新对象,这个过程有两种方式,即浅拷贝和深拷贝。
浅拷贝(Shallow Copy)只复制指针或引用,而不复制堆上的实际数据。它只是增加一个指向相同数据的指针或引用,也就是说,浅拷贝操作并不分配新内存给新对象。因此,原始对象和拷贝对象共享同一块内存,对一个对象的修改会影响另一个对象。当我们删除原始对象时,同时也会删除被拷贝对象的指针或引用,这可能会引起程序错误。
深拷贝(Deep Copy)则完全复制整个对象,包括堆上的实际数据。深拷贝会为新对象分配新的内存空间,并将原始对象的所有内容复制到新的内存空间。因此,拷贝对象和原始对象是完全独立的,互相没有影响。
总之,使用浅拷贝时,需要注意它们之间的关系,避免在一个对象上进行修改时影响到另一个对象;而深拷贝将创建一个全新的对象,避免了这个问题,但也需要更多的内存空间。