面向对象编程基于三个基本概念:数据抽象、继承和动态绑定。在C++中,用类进行数据抽象,用类派生从一个类继承另一个类:派生类继承基类的成员。动态绑定使编译器能够在运行时决定是使用基类中定义的函数还是派生类中定义的函数。
继承和动态绑定在两个方面简化了我们的程序:能够容易地定义与其他类相似但又不相同的新类(继承), 能够更容易地编写忽略这些相似类型之间区别的程序。 (C++ Primer)
virtual在需要进行动态绑定时使用。要触发动态绑定,必须满足两个条件:1、只有指定为虚函数的成员函数才能进行动态绑定,成员函数默认为是非虚函数,非虚函数不进行动态绑定;2、必须通过基类的引用或指针进行函数调用时动态绑定才发生。
举例说明:
C++ Primer中的书店管理系统为例:
基类:
class Item_base {
public:
Item_base(const std::string &book = "",
double sales_price = 0.0):
isbn(book), price(sales_price){}
std::string book() const { return isbn; }
virtual ~Item_base(){ }
private:
std::string isbn;
protected:
double price;
};
派生类1:Bulk_item1
class Bulk_item1 : public Item_base{
public:
Bulk_item1(const string &book = "", double sales_price = 0.0,
std::size_t qty = 0, double disc_rate = 0):
Item_base(book, sales_price), min_qty(qty), discount(disc_rate){}
double net_price(std::size_t cnt) const;
private:
std::size_t min_qty;
double discount;
};
Bulk_item1中net_price函数的定义
double Bulk_item1::net_price(size_t cnt) const
{
if(cnt >= min_qty)
return cnt*(1-discount)*price;
else
return cnt*price;
}
派生类2:Bulk_item2
class Bulk_item2 : public Item_base{
public:
Bulk_item2(const string &book = "", double sales_price = 0.0,
std::size_t qty = 0, double disc_rate = 0):
Item_base(book, sales_price), min_qty(qty), discount(disc_rate){}
double net_price(std::size_t cnt) const;
private:
std::size_t min_qty;
double discount;
};
派生类Bulk_item2的打折策略和Bulk_item1不同,需要重新定义。
double Bulk_item2::net_price(size_t cnt) const
{
if(cnt >=min_qty)
return min_qty*price + (cnt-min_qty)*(1-discount)*price;
else
return cnt*price;
}
最后定义函数print_total(),来显示书名,书的数量,以及书的总价格。这里动态绑定的运用出现了,我们不必定义几个不同的print_total()函数,分别来打印Item_base, Bulk_item1, Bulk_item2类对象的信息,直接使用一个Item_base类的引用作为参数,当传入Item_base、Bulk_item1、Bulk_item2不同类型的实参对象时,根据这些不同实参对象的具体类型来调用相应的函数,即实际对象的类型在运行时确定。print_total()的定义如下:
void print_total(ostream &os,const Item_base &item, size_t n)
{
os << "ISBN: " << item.book()
<< "\tnumber sold: " << n << "\ttotal price: "
<< item.net_price(n) << endl;
}
运行的结果如下: