虚拷贝

当传入对象时,函数有时会需要拷贝该对象并存入容器中,例如:

类定义:

 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     }  

 

posted @ 2018-02-28 17:31  鸭子船长  阅读(205)  评论(0编辑  收藏  举报