c++ 之容器与继承 - 实践

#include
#include
class Quote
{
	friend bool operator != (const Quote& lhs, const Quote& rhs);
public:
	Quote() = default;
	Quote(const std::string &book, double sale_price) :
		bookNo(book), price(sale_price) {
		std::cout << "Quote : constructing\n";
	}
	Quote(const Quote& q):bookNo(q.bookNo),price(q.price){
		std::cout << "Quote :copy constructing\n";
	}
	Quote& operator= (const Quote& q){
		if(this != &q) {  //自赋值
			bookNo = q.bookNo;
			price = q.price;
		}
		return *this;
	}
	Quote( Quote&& q) noexcept : bookNo(std::move(q.bookNo)), price(std::move(q.price))
	{
		std::cout << "Quote: move constructing\n";
	}
	std::string isbn() const { return bookNo; };
	virtual double net_price(std::size_t n) const
	{
		return n * price;
	}
	virtual ~Quote()
	{
		std::cout << "destructing Quote\n";
	}
private:
	std::string bookNo;//书编号
protected:
	double price = 0.0;
};
bool inline
operator != (const Quote& lhs, const Quote& rhs)
{
	return lhs.bookNo != rhs.bookNo &&
		lhs.price != rhs.price;
}
class Disc_quote : public Quote
{
public:
	Disc_quote();
	Disc_quote(const std::string& b, double p, std::size_t q, double d) :
		Quote(b, p), quantity(q), discount(d) {
		std::cout << "Disc_quote: constructing\n";
	}
	Disc_quote(const Disc_quote& dq):
		Quote(dq),quantity(dq.quantity),discount(dq.discount)
	{
		std::cout << "Disc_quote:copy constructing\n";
	}
	Disc_quote& operator=(const Disc_quote& rhs)
	{
		if (this != &rhs)
		{
			Quote::operator=(rhs);
			quantity = rhs.quantity;
			discount = rhs.discount;
		}
		return *this;
	}
	Disc_quote( Disc_quote&& dq) noexcept:
		Quote(std::move(dq)), quantity(std::move(dq.quantity)), discount(std::move(dq.discount))
	{
		std::cout << "Disc_quote:move constructing\n";
	}
	Disc_quote& operator=(const Disc_quote&& rhs)
	{
		if (this != &rhs)
		{
			Quote::operator=(rhs);
			quantity = std::move(rhs.quantity);
			discount = std::move(rhs.discount);
		}
		std::cout << "Disc_quote:move operator= constructing\n";
		return *this;
	}
	virtual double net_price(std::size_t n) const override = 0;
protected:
	std::size_t quantity;
	double      discount;
};
class Bulk_quote : public Disc_quote
{
public:
	Bulk_quote() = default;
	Bulk_quote(const std::string& book, double price, std::size_t qty,double disc):
		Disc_quote(book,price, qty, disc){
		std::cout << "Bulk_quote: constructing\n";
	}
	Bulk_quote(const Bulk_quote& bq) :Disc_quote(bq)
	{
		std::cout << "Bulk_quote: copy constructing\n";
	}
	Bulk_quote& operator=(const Bulk_quote& rhs)
	{
		Disc_quote::operator=(rhs);
		std::cout << "Bulk_quote: operator= \n";
		return *this;
	}
	double net_price(std::size_t n) const
	{
		return n * price*discount;
	}
	~Bulk_quote() override
	{
		std::cout << "destructing Bulk_quote\n";
	}
};
double print_total(std::ostream& os, const Quote& item, size_t n);
#include 
#include 
int main()
{
	/*Quote q("textbook", 10.6);
	Bulk_quote bq("textbook", 10.6, 10, 0.3);
	//Disc_quote qute;
	print_total(std::cout, q, 12);
	print_total(std::cout, bq, 12);*/
	std::vector v;
	for (unsigned i = 1; i != 10; ++i)
		v.push_back(Bulk_quote("sss", i * 10.1, 10, 0.3));
	double total = 0;
	for (const auto& b : v)
	{
		total += b.net_price(20);
	}
	std::cout << total << std::endl;
	std::cout << "======================\n\n";
	std::vector> pv;
	for (unsigned i = 1; i != 10; ++i)
		pv.push_back(std::make_shared(Bulk_quote("sss", i * 10.1, 10, 0.3)));
	double total_p = 0;
	for (auto p : pv)
	{
		total_p += p->net_price(20);
	}
	std::cout << total_p << std::endl;
	return 0;
}

输出为:

Quote : constructing
Disc_quote: constructing
Bulk_quote: constructing
Quote :copy constructing
Disc_quote:copy constructing
Bulk_quote: copy constructing
destructing Bulk_quote
destructing Quote
Quote : constructing
Disc_quote: constructing
Bulk_quote: constructing
Quote :copy constructing
Disc_quote:copy constructing
Bulk_quote: copy constructing
destructing Bulk_quote
destructing Quote
Quote : constructing
Disc_quote: constructing
Bulk_quote: constructing
Quote :copy constructing
Disc_quote:copy constructing
Bulk_quote: copy constructing
destructing Bulk_quote
destructing Quote
Quote : constructing
Disc_quote: constructing
Bulk_quote: constructing
Quote :copy constructing
Disc_quote:copy constructing
Bulk_quote: copy constructing
destructing Bulk_quote
destructing Quote
Quote : constructing
Disc_quote: constructing
Bulk_quote: constructing
Quote :copy constructing
Disc_quote:copy constructing
Bulk_quote: copy constructing
destructing Bulk_quote
destructing Quote
Quote : constructing
Disc_quote: constructing
Bulk_quote: constructing
Quote :copy constructing
Disc_quote:copy constructing
Bulk_quote: copy constructing
destructing Bulk_quote
destructing Quote
Quote : constructing
Disc_quote: constructing
Bulk_quote: constructing
Quote :copy constructing
Disc_quote:copy constructing
Bulk_quote: copy constructing
destructing Bulk_quote
destructing Quote
2727
destructing Bulk_quote
destructing Quote
destructing Bulk_quote
destructing Quote
destructing Bulk_quote
destructing Quote
destructing Bulk_quote
destructing Quote
destructing Bulk_quote
destructing Quote
destructing Bulk_quote
destructing Quote
destructing Bulk_quote
destructing Quote
destructing Bulk_quote
destructing Quote
destructing Bulk_quote
destructing Quote
destructing Quote
destructing Quote
destructing Quote
destructing Quote
destructing Quote
destructing Quote
destructing Quote
destructing Quote
destructing Quote

你的输出非常清晰地展示了 C++ 中值语义容器(vector<Quote>)与指针语义容器(vector<shared_ptr<Quote>>)在处理多态对象时的根本差异,同时也揭示了 std::vector 动态扩容时的移动语义行为

我们来逐段、逐行解析这个输出,理解每一行背后发生了什么。


一、整体结构

程序分两部分:

  1. 第一部分std::vector<Quote> v;
    → 值语义,发生 对象切片(slicing),多态失效。

  2. 第二部分std::vector<std::shared_ptr<Quote>> pv;
    → 指针语义,保留完整对象,多态生效。

输出顺序:

  • 先执行第一部分(构造 + 使用 + 析构)
  • 再执行第二部分(构造 + 使用 + 析构)

二、第一部分输出详解(vector<Quote> v

你循环 9 次,每次:

v.push_back(Bulk_quote("sss", i * 10.1, 10, 0.3));

✅ 每次插入的基本流程(以第 1 次为例):

Quote : constructing           ← 临时 Bulk_quote 的 Quote 基类构造
Disc_quote: constructing       ← Disc_quote 构造
Bulk_quote: constructing       ← Bulk_quote 构造(完整临时对象)
Quote: move constructing       ← vector 用移动构造切片出 Quote 对象
destructing Bulk_quote         ← 临时对象析构(派生类部分)
destructing Quote              ← 临时对象析构(基类部分)

✅ 这是 第 1 次插入,vector 容量从 0 → 1,无扩容,所以只有 1 次 move。


第 2 次插入(vector 扩容!)

初始容量可能为 1,插入第 2 个元素时需扩容(如 1 → 2):

Quote : constructing           ← 新临时 Bulk_quote 构造
Disc_quote: constructing
Bulk_quote: constructing
Quote: move constructing       ← 新元素 move 进 vector
Quote: move constructing       ← 旧元素(第1个)被 move 到新内存
destructing Quote              ← 旧 buffer 中的第1个元素析构
destructing Bulk_quote         ← 新临时对象析构
destructing Quote

✅ 所以你看到 2 次 move constructing:1 次新元素,1 次旧元素迁移。


第 3 次插入(容量 2 → 4?)

vector 容量策略通常是 2 倍增长。假设当前容量=2,插入第3个时扩容到4:

  • 需要 move 已有 2 个元素
  • 加上新元素 → 共 3 次 move constructing

输出:

Quote : constructing
Disc_quote: constructing
Bulk_quote: constructing
Quote: move constructing   ← 新元素
Quote: move constructing   ← 旧元素1
Quote: move constructing   ← 旧元素2
destructing Quote          ← 旧元素1析构
destructing Quote          ← 旧元素2析构
destructing Bulk_quote
destructing Quote

✅ 完全匹配你的输出!

posted on 2025-11-07 20:46  blfbuaa  阅读(4)  评论(0)    收藏  举报