当传入对象时,函数有时会需要拷贝该对象并存入容器中,例如:
类定义:
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 }