c/c++ 继承与多态 容器与继承3
程序员文章站
2022-04-08 11:37:30
"c/c++ 继承与多态 容器与继承2" 巩固了容器里放智能指针的用法,但是有个问题,对于使用Basket类的用户来说,必须添加的是智能指针,如果能直接添加一个普通的类的对象的话,用起来就方便的多了,所以改进一下Basket类的add_item接口。 新的接口:一个是拷贝给定的对象,另一个是移动对象 ......
巩固了容器里放智能指针的用法,但是有个问题,对于使用basket类的用户来说,必须添加的是智能指针,如果能直接添加一个普通的类的对象的话,用起来就方便的多了,所以改进一下basket类的add_item接口。
新的接口:一个是拷贝给定的对象,另一个是移动对象。
void add_item(const quote& sale);//左值拷贝 void add_item(quote&& sale);//右值移动
关键点:
1,由于类quote没有自定义的拷贝控制成员(拷贝构造函数,赋值语句等),所以,编译器才能自动生成移动构造函数,后面要用到编译器生成移动构造函数。
2,由于key是智能指针,所以在方法add_item里必须要有new,问题来了,new谁呢,只能new父类quote,但是new了quote后,子类部分就被切除掉了。
3,为了解决在2处的问题,在quote和它的子类里添加辅助的虚函数,来得到正确的指针。得到了正确的普通指针就可以用普通指针做出智能指针了。
quote4.h
#ifndef __quote4_h__ #define __quote4_h__ #include <iostream> class quote{ public: quote() = default; quote(const std::string& book, double pri) :bookno(book), price(pri){} std::string isbn() const{return bookno;} //调用此方法的对象是左值的时候 virtual quote* clone() const & { //调用合成的拷贝构造函数 return new quote(*this); } ///调用此方法的对象是右值的时候 virtual quote* clone() && { //调用合成的移动构造函数 return new quote(std::move(*this)); } virtual double net_price(std::size_t n)const{ return n * price; } virtual void debug()const{ std::cout << bookno << " " << price << std::endl; } 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 qyn, double disc):quote(book, price), quantity(qyn), discount(disc){} double net_price(std::size_t) const override = 0; protected: std::size_t quantity = 0;//折扣适用的数量 double discount = 0.0; //折扣率 }; class bulk_quote : public disc_quote{ public: bulk_quote() = default; bulk_quote(const std::string& book, double price, std::size_t qyn, double disc) :disc_quote(book, price, qyn, disc){} //调用此方法的对象是左值的时候 bulk_quote* clone() const & { //调用合成的拷贝构造函数 return new bulk_quote(*this); } ///调用此方法的对象是右值的时候 bulk_quote* clone() && { //调用合成的移动构造函数 return new bulk_quote(std::move(*this)); } double net_price(std::size_t) const override; }; class min_quote : public disc_quote{ public: min_quote() = default; min_quote(const std::string& book, double price, std::size_t qyn, double disc) :disc_quote(book, price, qyn, disc){} double net_price(std::size_t) const override; }; #endif
quote4.cpp
#include "quote4.h" double bulk_quote::net_price(std::size_t cnt) const{ if(cnt >= quantity){ return cnt * (1 - discount) * price; } else{ return cnt * price; } } double min_quote::net_price(std::size_t cnt) const{ if(cnt < quantity){ return cnt * (1 - discount) * price; } else{ return cnt * price; } }
basket2.h
#ifndef __basket2_h__ #define __basket2_h__ #include "quote4.h" #include <set> #include <memory> 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>(sale.clone())); } void add_item(quote&& sale){ items.insert(std::shared_ptr<quote>(std::move(sale).clone())); } double total_receipt(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}; }; #endif
basket2.cpp
#include "basket.h" double print_total(std::ostream& os, const quote& item, size_t n); double basket::total_receipt(std::ostream& os) const{ double sum = 0.0; for(auto iter = items.cbegin(); iter != items.cend(); iter = items.upper_bound(*iter)){ sum += print_total(os, **iter, items.count(*iter)); } os << "total sale: " << sum << std::endl; return sum; }
main.cpp
#include "quote4.h" #include "basket2.h" #include <vector> #include <iostream> double print_total(std::ostream& os, const quote& item, size_t n){ double ret = item.net_price(n); os << "isbn: " << item.isbn() << " # sold: " << n << " total due: " << ret << std::endl; return ret; } int main(){ basket bsk; quote q1("01", 100); bulk_quote bq1("01", 100, 2, 0.1); bsk.add_item(quote("01", 100)); bsk.add_item(bulk_quote("01", 100, 2, 0.1)); bsk.total_receipt(std::cout); }