派生类的作用域嵌套在基类之中.
在编译时进行的名字查找是由静态类型决定的.
关键概念:在进行函数调用时,假设我们使用p->mem(),则执行以下四个步骤.
首先确定p对应的静态类型,查找对应的mem,如果找不到,则依次在直接基类中不断查找直到到达继承链的顶端。如果找遍了任然找不到,则编译器将报错.
一旦找到,则判断mem是否是虚函数,如果是虚函数,则编译器将在运行时确定运行哪个虚函数的版本.
否则,将产生一个常规的函数调用.
===========================================
如果基类和派生类的虚函数不同,那么虚函数就不会覆盖基类中的虚函数,而是重新创建了一个新的函数.
===========================================
注意基类必须定义一个虚析构函数,这是因为在动态分配内存的时候有可能指针的静态类型和动态类型不一致.这时候我们需要知道执行哪一个析构函数.因此析构函数需要进行动态绑定.
======================================================================================
[练习]为Quote,disc_quote,bulk_quote定义它们自己的拷贝控制成员,要求添加打印语句,并且与合成版本的行为一致.
[1]在定义自己的拷贝成员时,必须调用基类的相应成员.否则会调用基类的默认构造函数来初始化派生类中基类的相应部分.
class Quote
{
public:
Quote() = default;//默认构造函数
Quote(const string& s, const double Sales_price) :bookNo(s), price(Sales_price){}//普通构造函数
Quote(const Quote& q) :bookNo(q.bookNo), price(q.price){ cout << "Quote(const Quote&)\n"; }//拷贝构造函数
/*****************************移动构造函数*************/
Quote(Quote&&q)NOEXCEPT :
bookNo(std::move(q.bookNo)), price(q.price){cout << "Quote(Quote&&)\n"; }
/******************拷贝构造函数*********************************/
Quote& operator=(const Quote& q){
bookNo = q.bookNo;
price = q.price;
cout << "operator=(Quote&)\n";
return *this;
}
/************************virtual析构函数************************/
virtual ~Quote(){ cout << "~Quote()\n"; };
virtual double net_price(size_t n)const { return price*n; }//虚函数,定义实际价格
virtual string net_price(string s)const { return bookNo; }
virtual void debug()const{
cout << "ISBN: " << isbn() << " single price: " << price ; }//显示成员
string isbn()const{ return bookNo; }
private:
string bookNo;
protected:
double price = 0;
};
/*********定义一个抽象基类*************/
class disc_quote :public Quote
{
public:
disc_quote() = default;
/********************普通构造函数*****************************/
disc_quote(const string&s, double single_price, size_t qty, double disc) :
Quote(s, single_price), quantity(qty), discount(disc){}
/********************拷贝构造函数,必须首先调用基类的拷贝构造函数*****************************/
disc_quote(const disc_quote& d) :Quote(d), quantity(d.quantity), discount(d.discount){
cout << "disc_quote(const disc_quote&)\n";
};
/*******************重载拷贝运算符号*****************************/
disc_quote& operator=(const disc_quote& d){
Quote::operator=(d);
quantity = d.quantity;
discount = d.discount;
cout << "operator=(const disc_quote&)\n";
return *this;
}
/********************析构函数:似乎不需要,因为基类已经定义了虚属性,只是为了输出语句*****************************/
~disc_quote(){ cout << "~disc_quote()\n"; };
/**************纯虚函数 net_price***************/
double net_price(size_t n)const = 0;
protected:
size_t quantity = 0;
double discount = 0;
};
class bulk_quote :public disc_quote//从quote继承
{
public:
/*****************定义派生类自己的构造函数***********************/
bulk_quote() = default;
/*****************定义派生类自己的普通构造函数***********************/
bulk_quote(const string& s, const double sales_price, size_t cnt, double disc) :
disc_quote(s, sales_price, cnt, disc){}
/********************拷贝构造函数*****************************/
bulk_quote(const bulk_quote& d) :disc_quote(d) { cout << "bulk_quote(const bulk_quote&)\n"; }
/*******************拷贝赋值运算符*****************************/
bulk_quote& operator=(const bulk_quote& rhs){
disc_quote::operator=(rhs);
cout << "operator=(const bulk_quote&)\n";
return *this;
}
/****************虚析构函数********************/
~bulk_quote(){ cout << "~bulk_quote()\n"; }
/********************覆盖了抽象基类的虚函数******************/
double net_price(size_t) const override;
/********************debug(),显示bulk_quote成员******************/
void debug()const override{
Quote::debug();
cout <<" min_quantity: " <<quantity<<"discount: "<<discount;
}
};
double bulk_quote::net_price(size_t cnt) const
{
if (cnt >= quantity)
return (1 - discount)*cnt*price;
else
return cnt*price;
}
======================================================================================