封装 -> 可读性
继承 -> 可扩充性
多态 -> 可重用性

多态:指同一名字的事物可以完成不同的功能。
编译时的多态:主要指函数的重载(包括运算符的重载)、对重载函数的调用,在编译时就能根据实参确定应该调用哪个函数,因此叫编译时的多态;
运行时的多态:和继承和虚函数有关。

#include <iostream>
using namespace std;

//基类People
class People{
public:
    People(char *name, int age);//声明构造函数 
    void display();
protected:
    char *m_name;
    int m_age;
};
//定义构造函数
People::People(char *name, int age): m_name(name), m_age(age){}  //构造函数初始化列表 
void People::display(){
    cout<<m_name<<"今年"<<m_age<<"岁了,是个无业游民。"<<endl;
}

//派生类Teacher
class Teacher: public People{
public:
    Teacher(char *name, int age, int salary);
    void display();
private:
    int m_salary;
};
Teacher::Teacher(char *name, int age, int salary): People(name, age), m_salary(salary){}
void Teacher::display(){
    cout<<m_name<<"今年"<<m_age<<"岁了,是一名教师,每月有"<<m_salary<<"元的收入。"<<endl;
}

int main(){
    People *p = new People("王志刚", 23);
    p -> display();

    p = new Teacher("赵宏佳", 45, 8200);
    p -> display();

    return 0;
}

//运行结果:
王志刚今年23岁了,是个无业游民。
赵宏佳今年45岁了,是个无业游民。

发现:当基类指针p指向派生类Teacher的对象时,虽然使用了Teacher的成因变量,但是却没有使用它的成员函数。

虚函数:让基类指针能够访问派生类的成因函数。

//更改上面的代码,将display()函数声明为虚函数。
#include <iostream>
using namespace std;

//基类People
class People{
public:
    People(char *name, int age);//声明构造函数 
    virtual void display();
protected:
    char *m_name;
    int m_age;
};
//定义构造函数
People::People(char *name, int age): m_name(name), m_age(age){}  //构造函数初始化列表 
void People::display(){
    cout<<m_name<<"今年"<<m_age<<"岁了,是个无业游民。"<<endl;
}

//派生类Teacher
class Teacher: public People{
public:
    Teacher(char *name, int age, int salary);
    virtual void display();
private:
    int m_salary;
};
Teacher::Teacher(char *name, int age, int salary): People(name, age), m_salary(salary){}
void Teacher::display(){
    cout<<m_name<<"今年"<<m_age<<"岁了,是一名教师,每月有"<<m_salary<<"元的收入。"<<endl;
}

int main(){
    People *p = new People("王志刚", 23);
    p -> display();

    p = new Teacher("赵宏佳", 45, 8200);
    p -> display();

    return 0;
}
//运行结果:
王志刚今年23岁了,是个无业游民。
赵宏佳今年45岁了,是一名教师,每月有8200元的收入。
  • 虚函数的作用:构成多态(唯一用处)

    • 基类指针指向基类对象时就使用基类的成员(包括成员函数和成员变量)
    • 基类指针指向派生类对象时就使用派生类的成员。
  • 多态:基类指针可以按照基类的方式来做事,也可以按照派生类的方式来做事,它有多种形态,或者说有多种表现形式,这种现象就是多态。

  • C++多态机制的目的:

    • 可以通过基类指针对所有的派生类(包括直接派生和间接派生)的成员变量和成员函数进行“全方位”的访问。
    • 如果没有多态,就只能访问成员变量。
  • 对象的内存模型是非常干净的,没有包含任何成员函数的信息,编译器是根据什么找到了成员函数? ------> 虚函数表

  • 借助引用也可以实现多态

    • 引用在本质上是通过指针的方式实现的
    • 借助指针可以实现多态,那么就有理由推断,借助引用也可以实现多态。
#include <iostream>
using namespace std;

//基类People
class People{
public:
    People(char *name, int age);//声明构造函数 
    virtual void display();
protected:
    char *m_name;
    int m_age;
};
//定义构造函数
People::People(char *name, int age): m_name(name), m_age(age){}  //构造函数初始化列表 
void People::display(){
    cout<<m_name<<"今年"<<m_age<<"岁了,是个无业游民。"<<endl;
}

//派生类Teacher
class Teacher: public People{
public:
    Teacher(char *name, int age, int salary);
    virtual void display();
private:
    int m_salary;
};
Teacher::Teacher(char *name, int age, int salary): People(name, age), m_salary(salary){}
void Teacher::display(){
    cout<<m_name<<"今年"<<m_age<<"岁了,是一名教师,每月有"<<m_salary<<"元的收入。"<<endl;
}

int main(){
	//实例化对象 
    People p("王志刚", 23);
    Teacher t("赵宏佳", 45, 8200);
    
    
    People &rp = p;
	People &rt = t; 
	
	rp.display();
	rt.display();

    return 0;
}

//运行结果:
王志刚今年23岁了,是个无业游民。
赵宏佳今年45岁了,是一名教师,每月有8200元的收入。

由于引用类似于常量,只能在定义的同时初始化,并且以后也要从一而终,不能再引用其他数据,所以本例中一定要定义两个引用变量,
一个用来引用基类对象,一个用来引用派生类对象。
从运行结果可以看出,当基类的引用指代基类对象时,调用的是基类的成员,当基类的引用指代派生类对象时,调用的是派生类的成员。

  • 一般谈及多态时是说指针

    • 因为引用不像指针灵活,指针可以随时改变方向,而引用只能指代固定的对象,在多态性方面缺乏表现力。
  • 多态的用途

    • 对于具有复杂继承关系的中大型程序,多态可以增加其灵活性,让代码更具有表现力。
#include <iostream>
using namespace std;

//军队
class Troops{
public:
    virtual void fight(){ cout<<"Strike back!"<<endl; }
};

//陆军
class Army: public Troops{
public:
    void fight(){ cout<<"--Army is fighting!"<<endl; }
};
//99A主战坦克
class _99A: public Army{
public:
    void fight(){ cout<<"----99A(Tank) is fighting!"<<endl; }
};
//武直10武装直升机
class WZ_10: public Army{
public:
    void fight(){ cout<<"----WZ-10(Helicopter) is fighting!"<<endl; }
};
//长剑10巡航导弹
class CJ_10: public Army{
public:
    void fight(){ cout<<"----CJ-10(Missile) is fighting!"<<endl; }
};

//空军
class AirForce: public Troops{
public:
    void fight(){ cout<<"--AirForce is fighting!"<<endl; }
};
//J-20隐形歼击机
class J_20: public AirForce{
public:
    void fight(){ cout<<"----J-20(Fighter Plane) is fighting!"<<endl; }
};
//CH5无人机
class CH_5: public AirForce{
public:
    void fight(){ cout<<"----CH-5(UAV) is fighting!"<<endl; }
};
//轰6K轰炸机
class H_6K: public AirForce{
public:
    void fight(){ cout<<"----H-6K(Bomber) is fighting!"<<endl; }
};

int main(){
    Troops *p = new Troops;
    p ->fight();
    //陆军
    p = new Army;
    p ->fight();
    p = new _99A;
    p -> fight();
    p = new WZ_10;
    p -> fight();
    p = new CJ_10;
    p -> fight();
    //空军
    p = new AirForce;
    p -> fight();
    p = new J_20;
    p -> fight();
    p = new CH_5;
    p -> fight();
    p = new H_6K;
    p -> fight();

    return 0;
}
//运行结果:
Strike back!
--Army is fighting!
----99A(Tank) is fighting!
----WZ-10(Helicopter) is fighting!
----CJ-10(Missile) is fighting!
--AirForce is fighting!
----J-20(Fighter Plane) is fighting!
----CH-5(UAV) is fighting!
----H-6K(Bomber) is fighting!
posted on 2020-02-19 23:44  xiaobaizzZ  阅读(152)  评论(0编辑  收藏  举报