面向对象编程的三个核心为数据抽象、继承和动态绑定。
继承:
派生类需要通过派生列表指明它从哪个或哪几个基类继承过来,这样,派生类将继承基类的所有成员(多继承将继承多个基类的所有成员)。
派生列表的访问控制符指明继承过来的成员是否对派生类对象可见,默认为public。
派生类除了继承基类的所有成员外,还会定义自己特殊的成员。
虚函数:基类希望某个或某些函数在派生类中被重写,就用关键字virtual指明某个或某些类为虚函数,表示这些成员函数在派生类中可能会被"重新定义"(函数名和形参表不变,仅函数体变化),如果派生后没有被"重新定义",虚函数与其他被继承的函数没什么区别,如果派生类中要对虚函数"重新定义",则在函数列表最后用关键字overite标识。重新定义后的函数被调用时是调用基类成员函数还是派生类重新定义的成员函数由调用对象类型来决定。除了构造函数外的非静态函数都可以定义为虚函数。
关键字virtual只能在基类内部的函数声明前,在类外定义函数时不能带virtual,且虚函数继承到派生类中后隐式的为虚函数。
动态绑定(运行时绑定):基类中声明为虚函数的成员,在派生类中被重写后,由于非重载(形参表一样),只能通过调用对象来判断调用基类还是派生类的成员函数。当我们使用基类的引用或指针来调用虚函数时将发生动态绑定。
//基类
class Quote {
public:
Quote() = default;
Quote(string bn, double pr) :bookNo(bn),price(pr) {}
string isbn()const{ return bookNo; }
virtual double net_price(std::size_t n) const { return n * price; }
private:
string bookNo="";
protected:
double price = 0;
};
//派生类
class Bulk_quote:public Quote {
public:
Bulk_quote() = default;
Bulk_quote(string bn,double pr,size_t min,double dis):Quote(bn,pr),min_qty(min),discount(dis) {}
double net_price(size_t n)const override {
if (n > min_qty)
return n * price * (1 - discount);
return n * price;
}
private:
size_t min_qty = 0;
double discount = 0;
};
//调用
int main() {
Quote quote("红楼梦", 30);
Bulk_quote bulk_quote("红楼梦", 30, 2, 0.1);
cout << quote.net_price(3) << endl;
cout << bulk_quote.net_price(3) << endl;
return 0;
}
派生类对继承成员的访问控制:
派生类继承基类的成员后,派生类的成员并不一定有权访问从基类中继承的成员。派生类对继承成员的访问控制与其他用户(对象)对基类的访问控制是一样的(仅public和private相同),即派生类只能访问基类中为public的成员,不能private成员,另外,还有一种protected 成员,能被派生类访问,但不能被其他用户访问。
(注意与派生列表中的继承方式区分,继承方式的访问控制符是控制继承过来的成员是否对派生类用户可见的,默认为private方式继承,派生类对象不能访问继承过来的成员。)
派生类到基类的类型转换:
由于派生类继承了基类的成员,所以在需要基类对象或基类对象的引用、指针的地方可以用派生类对象或者派生类对象的引用、指针来代替。即派生类对象或对象的引用、指针可以转化为基类对象或基类对象的引用、指针。
Qutote quote;
Bulk_quotye bulk_quote;
Quote *qo=&bulk_quote; //派生类指针向基类指针转换,qo指针指向了派生类中的基类部分
Quote &qoo=bulk_quote; //派生类引用向基类引用转换,引用qoo绑定了派生类中的基类部分
//
Bulk_quote bulk_quote("红楼梦", 30, 2, 0.1);
Quote quote = bulk_quote; //派生类对象向基类对象转换,quote对象成员为派生类对象中基类部分的copy
派生类的构造函数
派生类的构造函数对成员初始化时应该遵循这样的原则:每个类仅负责自己成员的初始,派生类应遵循基类的接口,对于继承过来的基类成员,应该调用基类的构造函数进行初始化。
初始化顺序:先初始化基类的成员,然后按照声明顺序依次初始化派生类的成员。这样一个自上而下的过程。
Bulk_quote(string bn, double pr, size_t min, double dis) :Quote(bn, pr), min_qty(min), discount(dis) {}
派生类与静态成员
类的静态成员只存在于类中,对象中不存在静态成员的任何数据,且静态成员仅存在唯一实例,只能被初始化一次。而且声明周期为整个程序的始终。
基类中定义的静态成员可以被派生类继承,但仅存在唯一实例。
如果派生类能访问基类静态成员时(需是public或protected的基类成员),派生类成员对基类中静态成员的访问方式:
派生类的声明:class 类名;
注意:派生类声明不能加上派生列表(声明语句的存在仅用于告诉程序某个名字的存在以及这个名字是一个什么类型的实体,声明语句不应该加上具体的细节)
作为基类的条件和防止被继承的方法
防止继承的方法:如果不希望某个类被用作基类,可以在类定义时,在类名后加关键字final,可以限制此类被用作基类。
作为基类的条件:无final关键字且已被定义的类都可以作为基类,注意,仅声明而未定义的类不可以作为基类。
class NoDerived final{/* */}; //NoDerived不能用作基类
标签:OPP,函数,继承,quote,成员,基类,第十五章,面向对象编程,派生类 From: https://www.cnblogs.com/newlyx/p/16618150.html