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动态扩容时的移动语义行为。我们来逐段、逐行解析这个输出,理解每一行背后发生了什么。
一、整体结构
程序分两部分:
第一部分:
std::vector<Quote> v;
→ 值语义,发生 对象切片(slicing),多态失效。第二部分:
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✅ 完全匹配你的输出!
浙公网安备 33010602011771号