0%

C++ 拷贝构造

拷贝构造函数

  • 拷贝构造函数是构造函数的一种
  • 当利用一个已经存在的对象创建一个新的对象时(类似于拷贝)看, 就会调用新对象的拷贝构造函数进行初始化
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 car2(car1);
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() {
/*const char* name = "bmw";
cout << name << endl;
char name2[] = { 'b', 'm', 'w', '\0', 's' };
cout << name2 << endl;
cout << strlen(name2) << endl;*/
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() {
//cout << "********" << endl;
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 指向了不同的堆空间的地址值,存储的字符串相同

求大佬赏个饭