带你粗略了解C++中的深浅拷贝
目录
- 一.背景
- 二.代码实现
- 三.问题
- 四.解决方法
- 总结
一. 背景
首先看这样一个问题,在Car类中聚合了Engine类
二. 代码实现
下面给出类Car与类Engine的定义
Car.h
#ifndef COPY__CAR_H_ #define COPY__CAR_H_ #include "Engine.h" #include <string> using namespace std; class Car { public: // 构造函数 Car(); Car(string brand, int version); ~Car(); // 添加或者修改一个引擎 void setEngine(string engine_brand, int engine_version); // 对汽车信息进行描述 string description() const; private: string brand; // 品牌 int version; // 型号 Engine *engine; // 引擎 }; #endif //COPY__CAR_H_
Car.cpp
#include "Car.h" #include <sstream> Car::Car() { this->brand = "无"; this->version = 0; this->engine = nullptr; } Car::Car(string brand, int version) { engine = nullptr; this->brand = brand; this->version = version; } Car::~Car() { } void Car::setEngine(string engine_brand, int engine_version) { if (engine) { delete engine; } engine = new Engine(engine_brand, engine_version); } string Car::description() const { stringstream result; result << "品牌:" << brand << " 版本:" << version << engine->description(); return result.str(); }
Engine.h
#ifndef COPY__ENGINE_H_ #define COPY__ENGINE_H_ #include <string> using namespace std; class Engine { public: Engine(); Engine(string brand, int version); ~Engine(); string description() const; private: string brand; int version; }; #endif //COPY__ENGINE_H_
Engine.cpp
#include "Engine.h" #include <sstream> Engine::Engine() { this->brand = "无"; this->version = 0; } Engine::Engine(string brand, int version) { this->brand = brand; this->version = version; } Engine::~Engine() { } string Engine::description() const { stringstream result; result << " 发动机品牌:" << brand << " 发动机版本:" << version; return result.str(); }
在大部分情况下,在类中不去实现拷贝构造函数是可行的,C++编译器会帮助我们自动生成一个拷贝构造函数. 并且这个拷贝构造函数足以应对很多问题,但是当遇到指针的时候情况变得不同.下面给一个示例代码:
#include "Car.h" #include <iostream> using namespace std; int main() { // 创建car_1对象 Car car_1("宝马", 1); // 为car_1对象添加一个引擎 car_1.setEngine("宝马", 1); // 创建car_2对象, 并且拷贝自car_1 Car car_2(car_1); // 输出修改引擎前的两个对象信息 cout << car_1.description() << endl; cout << car_2.description() << endl; // 修改引擎 car_2.setEngine("奔驰", 1); // 输出修改引擎以后的两个对象信息 cout << car_1.description() << endl; cout << car_2.description() << endl; return 0; }
三. 问题
当我们对car_2对象的引擎进行修改时, 我们所期望的结果是仅仅只有car_2对象的引擎被修改,可是事实如此吗?
结果显示,并不是这样,car_1对象的引擎和car_2对象的引擎都被改变了.
原因就是C++编译器帮我们合成的拷贝构造函数是一个浅拷贝,只是将变量的值拷贝过来,在Car类中的成员变量engine是一个指针变量,存放的是一个地址.在进行拷贝构造时,就意味着car_1对象中engine变量和car_2对象中的engine变量存放的是同一个地址值(由于是new出来的对象, 所以地址engine变量中存放的值处于堆空间). 如图所示.(地址是瞎编的)
四. 解决方法
解决方法就是:手动实现拷贝构造函数,实现深拷贝,如图所示.
在Car.cpp文件中添加如下代码 :
Car::Car(const Car &other) { this->brand = other.brand; this->version = other.version; engine = new Engine(other.brand, other.version); }
主函数不变,得到如下结果:
总结
本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注海外IDC网的更多内容!
【文章原创作者:美国服务器 http://www.558idc.com/mg.html提供,感恩】