C++,  技术学习

C++多态

什么是多态?

多态的意思就是做同一件事情, 不同的对象产生不同的结果. 比如坐车的时候, 成人全票, 1.2以下免票.
其实函数重载也可以算作是多态的一种形式.

继承中的多态

函数重载我们已经讨论过了, 所以我们重点来看看在继承中如何实现多态.

构成多态的条件

在继承中构成多态需要满足两个条件:
1. 必须通过基类指针或者引用调用虚函数.
2. 被调用的必须是虚函数, 而且派生类中必须重写虚函数.

虚函数与虚函数重写

什么是虚函数?
被virtual修饰的函数就是虚函数

class Animal{
public:
    virtual void func(){ //虚函数
        cout<<"你不是人"<<endl;
    }
};
class Person : public Animal{
    virtual void func(){ //虚函数的重写
        cout<<"你是人"<<endl;
    }
};

虚函数的重写需要在派生类中完成, 而且派生类虚函数的返回值, 函数名称, 参数列表必须完全相同.

虚函数重写的特例

1.协变

协变的含义是派生类在重写虚函数时, 其返回值类型与基类虚函数返回值类型不同.
基类返回基类指针或引用, 派生类返回派生类指针或引用.

class A{};
class B:public A{};

class Animal{
public:
    virtual A* func(){ 
        cout<<"你不是人"<<endl;
        return new A;
    }
};
class Person : public Animal{
    virtual B* func(){ //返回值类型不需要一定是Person*类型, 也就是说, 
                       //只要返回值类型构成了继承, 就可以作为发生协变的返回值.
        cout<<"你是人"<<endl;
        return new B;
    }
};

2.析构函数

如果基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加virtual关键字,都与基类的析构函数构成重写,虽然基类与派生类析构函数名字不同。虽然函数名不相同,看起来违背了重写的规则,其实不然,这里可以理解为编译器对析构函数的名称做了特殊处理,编译后析构函数的名称统一处理成destructor。

class Person {
public:
    virtual ~Person() {
        cout << "~Person()" << endl;
    }
};
class Student : public Person {
public:
    virtual ~Student() {
        cout << "~Student()" << endl; 
    }
};
// 只有派生类Student的析构函数重写了Person的析构函数,下面的delete对象调用析构函数,才能构成多态,才能保证p1和p2指向的对象正确的调用析构函数。

纯虚函数与抽象类

在虚函数的后面写上 = 0 ,则这个函数为纯虚函数. 包含纯虚函数的类叫做抽象类, 抽象类不能实例化出对象。派生类继承后也不能实例化出对象,只有重写纯虚函数,派生类才能实例化出对象。纯虚函数规范了派生类必须重写.

class Car{
public:
    virtual void Drive() = 0;//纯虚函数
};

class Benz :public Car{
public:
    virtual void Drive(){
        cout << "Benz-舒适" << endl;
    }
};

class BMW :public Car{
public:
    virtual void Drive(){
        cout << "BMW-操控" << endl;
    }
};
void Test(){
    Car* pBenz = new Benz;
    pBenz->Drive();
    Car* pBMW = new BMW;
    pBMW->Drive();
}

函数重载和虚函数重写的区别

函数重载:

  • 在同一作用域中
  • 形参列表(参数个数 或 类型 或 顺序)必须不同
  • 函数名相同

虚函数重写

  • 必须是虚函数
  • 函数名 参数列表 返回值必须相同
  • 分别在基类和派生类的作用域

留言

您的电子邮箱地址不会被公开。 必填项已用*标注