拷贝构造函数
- 拷贝构造函数是构造函数的一种
- 当利用一个已经存在的对象创建一个新的对象时(类似于拷贝)看, 就会调用新对象的拷贝构造函数进行初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Car { int m_price; int m_length; public: Car(int price = 0, int length = 0) : m_price(price), m_length(length) { cout << "Car_____"; cout << m_price << "*****" << m_length << endl; } Car(const Car& car) : m_price(car.m_price), m_length(car.m_length){ cout << "const Car& car" << endl; } void display() { cout << "price = " << m_price << ", length = " << m_length << endl; }
};
|
调用父类的拷贝构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #include <iostream> using namespace std;
class Person { public: int m_age; Person(int age = 0) : m_age(age) {} Person(const Person& person) : m_age(person.m_age ) {} };
class Student : public Person { public: int m_score; Student(int age = 0, int score = 0) : Person(age), m_score(score) {}; Student(const Student &student) :Person(student), m_score(student.m_score){} };
int main() { Student stu1(18, 100); Student stu2(stu1);
cout << stu2.m_age << endl; cout << stu2.m_score << endl;
return 0; }
|
注意点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| #include <iostream> using namespace std;
class Car { int m_price; int m_length; public: Car(int price = 0, int length = 0) : m_price(price), m_length(length) { cout << "Car(int price = 0, int length = 0)" << endl; } Car(const Car& car) : m_price(car.m_price), m_length(car.m_length) { cout << "Car(const Car& car)" << endl; } void display() { cout << "price = " << m_price << ",length=" << m_length << endl; } };
int main() { Car car1(100, 5); Car car2(car1); Car car3 = car2; Car car4; car4 = car3; car4.display();
return 0; }
|
浅拷贝
编译器默认提供的拷贝是浅拷贝(shallow copy)
- 将一个对象中所有成员变量的值拷贝到另一个对象
- 如果某个成员变量是个指针,之后拷贝指针中存储的地址值,并不会拷贝指针对象所指向的内存空间
- 可能会导致堆空间多次free的问题
存在的问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| #include <iostream> using namespace std;
class Car { int m_price; char* m_name; public: Car(int price = 0, char* name = NULL) : m_price(price), m_name(name) {
} void display() { cout << "price is" << m_price << ", name is " << m_name << endl; } };
Car* g_car; void test() { char name2[] = { 'b', 'm', 'w', '\0' }; g_car = new Car(100, name2);
}
int main() {
test(); g_car->display();
char name2[] = { 'b', 'm', 'w', '\0' }; Car* car = new Car(100, name2); car->display();
return 0; }
|
解决堆空间指向栈空间的问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #include <iostream> #include <cstdio> using namespace std;
class Car { int m_price; char* m_name; public: Car(int price = 0, char* name = NULL) :m_price(price) { if (name == NULL) return; m_name = new char[strlen(name) + 1] {}; strcpy(m_name, name); } ~Car() { if (m_name == NULL) return; delete[] m_name; m_name = NULL; } void display() { cout << "price is " << m_price << ", name is " << m_name << endl; } };
Car* g_car; void test() { char name2[] = "bwm"; g_car = new Car(100, name2); }
int main() { test(); g_car->display();
return 0; }
|
深拷贝
- 将指针指向的内容拷贝拷贝到新的存储空间
- 实现深拷贝,必须自定义拷贝构造函数
- 将指针类型的成员变量所指向的内存空间,拷贝到新的内存空间
1 2 3 4 5 6
| Car(const Car& car) :m_price(car.m_price) { if (car.m_name == NULL) return; m_name = new char[strlen(car.m_name) + 1]{}; strcpy(m_name, car.m_name); }
|
这样就可以完成深拷贝,完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| #include <iostream> #include <cstdio> using namespace std;
class Car { int m_price; char* m_name; void copy(const char *name = NULL) { if (name == NULL) return; m_name = new char[strlen(name) + 1]{}; strcpy(m_name, name); } public: Car(int price = 0, const char* name = NULL) :m_price(price) { copy(name); } Car(const Car& car) :m_price(car.m_price) { copy(car.m_name); } ~Car() { if (m_name == NULL) return; delete[] m_name; m_name = NULL; } void display() { cout << "price is " << m_price << ", name is " << m_name << endl; } };
Car* g_car; void test() { char name2[] = "bwm"; g_car = new Car(100, name2); delete g_car; g_car = new Car(100, "haha"); }
int main() { Car car1(100, "bmw"); Car car2 = car1; car2.display();
return 0; }
|
注意到car1.m_name 和 car2.m_name 指向了不同的堆空间的地址值,存储的字符串相同