C++中复制(copy) 和 虚复制(virtual copy) 的 区别2014-11-20在继承过程中, 需要区分复制(copy)和虚复制(virtual copy);在派生类转换为基类时, 复制(copy)有可能切掉(sliced down)派生对象的派生部分, 只保留基类部分, 使派生类的虚函数无法使用;为了避免此情况, 如果传入是对象, 则可以定义虚函数clone, 使派生类继承此虚函数, 再传入容器, 可以重载方法;另外, 如果传入是实参, 使用shared_ptr<Base>配合make_shared<Derived>添加容器, 也可以进行动态绑定;再传入容器中, 容器会自动调用派生类的重载方法, 实现动态绑定;注意: 引用限定符(reference qualifier) GCC 4.8.1 才能支持;代码:
/** CppPrimer.cpp**Created on: 2013.11.12*Author: Caroline*//*eclipse cdt*/#include <iostream>#include <string>#include <vector>#include <set>#include <utility>#include <memory>#include <cstddef>using namespace std;class Quote;class Quote {public:Quote() = default;Quote (const std::string& book, double sales_price) :bookNo (book), price (sales_price) {}void add_item (const Quote& sale);std::string isbn() const { return bookNo; }virtual double net_price (std::size_t n) const { return n* price; } //虚函数virtual Quote* clone() const & {return new Quote(*this);}virtual Quote* clone() && {return new Quote(std::move(*this));}virtual ~Quote() = default; //动态绑定析构器private:std::string bookNo;protected: //受保护类型double price = 0.0;};class Disc_quote : public Quote { //抽象基类public:Disc_quote() = default;Disc_quote (const std::string& book, double price, std::size_t qty, double disc) :Quote(book, price), quantity (qty), discount (disc) {}double net_price (std::size_t) const = 0; //纯虚函数protected:std::size_t quantity = 0;double discount = 0.0;};class Bulk_quote final : public Disc_quote { //final限定词, 无法被继承public:Bulk_quote() = default;Bulk_quote(const std::string& book, double p, std::size_t qty, double disc) :Disc_quote(book, p, qty, disc) {} //使用基类的构造器double net_price(std::size_t cnt) const override;virtual Bulk_quote* clone() const & {return new Bulk_quote(*this);}virtual Bulk_quote* clone() && {return new Bulk_quote(std::move(*this));}};double Bulk_quote::net_price(std::size_t cnt) const{if (cnt >= quantity)return cnt * (1-discount) * price;elsereturn cnt * price;}double print_total(std::ostream &os, const Quote& item, std::size_t n){double ret = item.net_price(n);os << "ISBN: " << item.isbn() << " # sold: " << n << " total due: " << ret << std::endl;return ret;}class Basket {public:void add_item (const std::shared_ptr<Quote> &sale) { items.insert(sale); }void add_item (const Quote& sale){//items.insert(std::shared_ptr<Quote>(new Quote(sale))); //不会动态绑定items.insert(std::shared_ptr<Quote>(sale.clone()));}void add_item (Quote&& sale){//items.insert(std::shared_ptr<Quote>(new Quote(std::move(sale)))); //不会动态绑定items.insert(std::shared_ptr<Quote>(std::move(sale).clone()));}double total_reciept (std::ostream&) const;private:static bool compare (const std::shared_ptr<Quote> &lhs,const std::shared_ptr<Quote> &rhs){ return lhs->isbn() < rhs->isbn(); };std::multiset<std::shared_ptr<Quote>, decltype(compare)*> items{compare};};double Basket::total_reciept(std::ostream &os) const{double sum = 0.0;for(auto iter = items.cbegin(); iter != items.cend();iter = items.upper_bound(*iter)) { //跳过同名书, 直接计算countsum += print_total(os, **iter, items.count(*iter)); //*it是shared_ptr; **it是object}os << "Total Sale: " << sum << std::endl;return sum;}int main (void) {Basket bsk;/*bsk.add_item(std::make_shared<Quote>("CppPrimer", 45));bsk.add_item(std::make_shared<Bulk_quote>("EffectiveCpp", 50, 2, 0.15));bsk.add_item(std::make_shared<Bulk_quote>("EffectiveCpp", 50, 2, 0.15));bsk.add_item(std::make_shared<Bulk_quote>("EffectiveCpp", 50, 2, 0.15));*/bsk.add_item(Quote("CppPrimer", 45));bsk.add_item(Bulk_quote("EffectiveCpp", 50, 2, 0.15));bsk.add_item(Bulk_quote("EffectiveCpp", 50, 2, 0.15));bsk.add_item(Bulk_quote("EffectiveCpp", 50, 2, 0.15));bsk.total_reciept(std::cout);return 0;}
输出:
ISBN: CppPrimer # sold: 1 total due: 45ISBN: EffectiveCpp # sold: 3 total due: 127.5Total Sale: 172.5
作者:csdn博客 Spike_King