核心思想:数据抽象、继承和动态绑定。
数据抽象:将类的接口和实现分离。
继承:可以定义相同类型并对其相似关系建模。
动态绑定:可以再一定程度上忽略相似类型的区别,从而以统一的方式使用他们的对象。
目录
五 类型转换与继承(重要 五颗星)书(c++primer)534页
目录
一 继承
通过继承联系在一起的类构成一种层次关系。基类是父类。其他通过基类继承而来称为派生类,熟称子类。
c++中,基类存在两种函数:
一种是基类希望其派生类进行覆盖的函数,这种通常被定义成虚函数。当我们使用指针或者引用去调用虚函数时,该调用将被动态绑定。(关键字:virtual)
第二种是希望派生类直接继承而不要改变的函数。、
1:继承与静态成员函数
对于静态成员函数,只存在该成员的唯一定义。
派生类对象能够访问基类的静态成员函数
/*
静态成员函数只存在唯一的定义。
*/
class Base{
public:
static void statment();
};
class Derived:public Base{
void f(const Derived &);
};
void Derived::f(const Derived &derived_obj){
Base::statment(); //Base定义了statment()
Derived::statment();//Derived继承了statment()
derived_obj.statment();//通过派生类对象访问 。派生类对象能够访问基类的静态成员函数
statment();//通过this指针访问
}
二 动态绑定
print(cout,basic,20) ;//baisc 是类A的的对象
print(cout,bulk,20);//bulk是类B的对象
第一条调用的是类A的print 第二条调用的是类B的调用。
在c++语句中,当我么您使用基类的引用或者指针调用一个虚函数时将发生动态绑定
三 基类
基类必须是定义而非声明
class Quote;//只声明而非定义
每个派生类都会继承其直接基类的成员。最终的派生类会包含他的直接基类的子对象以及每个间接基类的子对象。
四 派生类
1:派生类对象以及派生类向基类的类型转换
Quote item; //Quote基类的对象
Bulk_quote bulk;//Bulk_quote派生类的对象
Quote *p=&item;//将p指向基类对象
p=&bulk;//p指向派生类的Quote部分
Quote &r=bulk;//r绑定到派生类的Quote部分
这种转换通常叫做 派生类到基类的类型转换。
这种隐式特性意味着我们可以把派生类对象或者派生类对象的引用用在需要基类引用的地方。同样也可以把派生类对象的指针用在需要基类指针的地方。
2:派生类构造函数
派生类必须使用基类的构造函数来初始化它的基类部分。
#include <iostream>
using namespace std;
/*
*案例说明
* Quote为原价出售的书籍
* Bulk_quote为打折出售的书籍
*/
//基类
class Quote
{
public:
Quote(const std::string &book,double sales_price):bookNo(book),price(sales_price){}
std::string isbn()const; //书籍编号
virtual double net_price(std::size_t n)const;//书籍实际销售价格
private:
std::string bookNo;
protected:
double price;
};
//派生类
class Bulk_quote :public Quote{
public:
Bulk_quote(const std::string &book,double p,std::size_t qty,double disc):Quote(book,p),min_qty(qty),discount(disc){}
double net_price(std::size_t n)const override;
private:
std::size_t min_qty;
double discount ;
};
/*
* 动态绑定
* 通过使用动态绑定,我们能使用同一段代码分别处理基类和派生类的对象
*
* 案例说明
* 例如当要购买的书籍和数量是已知的,下列函数负责打印书籍的总价
*/
3:派生类使用基类成员
派生类可以访问基类的公有和受保护成员。
派生类作用域嵌套在基类的作用域之中。因此,派生类的成员函数使用其派生类成员的方式与使用其基类成员的方式是一致的
double Bulk_quote::net_price(std::size_t cnt)const{
if(cnt>=min_qty){
return cnt*(1-discount)*price;
}else{
return cnt*price;
}
}
五 类型转换与继承(重要 五颗星)书(c++primer)534页
理解基类和派生类之间的类型转换是理解c++面向对象编程的关键所在
我们可以用Quote &指向一个Bulk_quote对象,也可以把一个Bulk_quote对象的地址赋给一个Quote*。
1:将基类的指针或者引用绑定到一个派生类对象的含义:当使用基类的引用或者指针时,实际上我们并不清楚改引用或者指针所绑定对象的真实类型。
2:当我们使用存在继承关系的类型时,必须将一个变量或其他表达式的静态类型与该表达式表示对象的动态类型区分。基类的指针或引用的静态类型可能与其动态类型不一致。
例如:某个函数 double print_total(ostream &os ,const Quote & item,size_t n){
double ret =item.net_price(n);
}此时 ,item的静态类型是Quote& ,动态类型是绑定的实参。如果我们给一个Bulk_quote类型的对象给这个函数,则item的静态类型和动态类型不一致。如前所述,item的静态类型是Queto&,而在此例中它的动态类型是Bulk_quote。如果表达式既不是引用也不是指针,则它的动态类型永远和静态类型一致。
3:不存在从基类向派生类的隐式类型转换。
例如:基类 Quote 派生类 Bulk_quote
Quote base;
Bulk_quote bulk;
Bulk_quote *bulkp=&base;//错误 不能将基类对象转换成派生类类型
Bulk_quote &bulkp2=base;//错误;不能将基类对象转换成派生类类型
Quote *p=&bulk;//正确 ,可以将派生类对象转换成基类类型 ,p指向bulk的Quote部分
Quote *p=&base;//正确 ,可以将派生类对象转换成基类类型 ,p指向Quote对象
p=&bulk;//正确 ,可以将派生类对象转换成基类类型 ;p指向bulk的Quote部分
Quote &p=bulk;//正确 ,可以将派生类对象转换成基类类型 ;p绑定bulk的Quote部分
4:对象之间不存在类型转换