虚拷贝
当传入对象时,函数有时会需要拷贝该对象并存入容器中,例如:
类定义:
1 class Quote { 2 public: 3 Quote() = default; 4 Quote (const std::string& book, double sales_price) : 5 bookNo (book), price (sales_price) {} 6 void add_item (const Quote& sale); 7 std::string isbn() const { return bookNo; } 8 virtual double net_price (std::size_t n) const { return n* price; } //虚函数 9 virtual Quote* clone() const & {return new Quote(*this);} 10 virtual Quote* clone() && {return new Quote(std::move(*this));} 11 virtual ~Quote() = default; //动态绑定析构器 12 private: 13 std::string bookNo; 14 protected: //受保护类型 15 double price = 0.0; 16 }; 17 18 class Disc_quote : public Quote { //抽象基类 19 public: 20 Disc_quote() = default; 21 Disc_quote (const std::string& book, double price, std::size_t qty, double disc) : 22 Quote(book, price), quantity (qty), discount (disc) {} 23 double net_price (std::size_t) const = 0; //纯虚函数 24 protected: 25 std::size_t quantity = 0; 26 double discount = 0.0; 27 }; 28 29 class Bulk_quote final : public Disc_quote { //final限定词, 无法被继承 30 public: 31 Bulk_quote() = default; 32 Bulk_quote(const std::string& book, double p, std::size_t qty, double disc) : 33 Disc_quote(book, p, qty, disc) {} //使用基类的构造器 34 double net_price(std::size_t cnt) const override; 35 virtual Bulk_quote* clone() const & {return new Bulk_quote(*this);} 36 virtual Bulk_quote* clone() && {return new Bulk_quote(std::move(*this));} 37 };
函数定义:
1 void add_item(const Quote& sale); //拷贝给定的对象 2 void add_item(Quote&& sale); //移动给定的对象
然而此时,add_item并不知道要分配的类型。当add_item进行内存分配时,它将拷贝sale参数,如
new Quote(sale)
然而这条表达式却可能是不正确的:new为我们请求的类型分配内存,因此它将分配一个Quote类型的对象并拷贝sale的Quote部分,然而sale实际指向的可能是Bulk_quote对象,此时add_item所拷贝的对象将失去一部分信息。
为了解决该问题,我们给Quote类添加了一个虚函数,该函数将申请一份当前对象的拷贝。
1 class Quote { 2 public: 3 virtual Quote* clone() const & { return new Quote(*this); } 4 virtual Quote* clone() && {return new Quote(std::move(*this)); } 5 }; 6 class Bulk_quote final : public Disc_quote { 7 public: 8 virtual Bulk_quote* clone() const & { return new Bulk_quote(*this); } 9 virtual Bulk_quote* clone() && {return new Bulk_quote(std::move(*this)); } 10 };
这样每个clone函数分配当前类型的一个新对象,其中,const左值引用成员将它自己拷贝给新分配的对象;右值引用成员则将自己移动到新数据中。
这样,我们可以使用clone写出新版本的add_item:
1 void add_item (const Quote& sale) 2 { 3 //items.insert(std::shared_ptr<Quote>(new Quote(sale))); //不会动态绑定 4 items.insert(std::shared_ptr<Quote>(sale.clone())); 5 } 6 void add_item (Quote&& sale) 7 { 8 //items.insert(std::shared_ptr<Quote>(new Quote(std::move(sale)))); //不会动态绑定 9 items.insert(std::shared_ptr<Quote>(std::move(sale).clone())); 10 }
联系方式:emhhbmdfbGlhbmcxOTkxQDEyNi5jb20=
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了