1.多态概念
多态是C++面面向对象的三大特性之一,多态需要在继承状态下完成,多态的特性就是面对相同的事情,需要不同的处理,产生不同的结果。
2.多态的条件及实现
多态是在不同的继承关系里,去实现函数名相同的不同实现方法,
在继承中实现多态需要两个条件:
- 必须通过基类的指针或引用来调用虚函数;
- 被调用的必须是虚函数,且派生类必须对基类的虚函数进行重写。
虚函数:
即在virtual修饰下的类成员函数称为虚函数
class Person { public: virtual void BuyTicket() { cout << "买票-全价" << endl;} };
虚函数重写:
虚函数的重写(覆盖):派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型、函数名字、参数列表完全相同),称子类的虚函数重写了基类的虚函数。
虚函数重写特列:
1. 协变(基类与派生类虚函数返回值类型不同)
派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。2.析构函数的重写(基类与派生类析构函数的名字不同)
如果基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加virtual关键字,都与基类的析构函数构成重写,虽然基类与派生类析构函数名字不同。虽然函数名不相同,看起来违背了重写的规则,其实不然,这里可以理解为编译器对析构函数的名称做了特殊处理,编译后析构函数的名称统一处理成destructor。C++11 override 和 final
从上面可以看出,C++对函数重写的要求比较严格,但是有些情况下由于疏忽,可能会导致函数名字母次序写反而无法构成重载,而这种错误在编译期间是不会报出的,只有在程序运行时没有得到预期结果才来debug会得不偿失,因此:C++11提供了override和final两个关键字,可以帮助用户检测是否重写。
多态实现:
class Person {
public:virtual void BuyTicket() { cout << "买票-全价" << endl; }virtual void Fun1() { cout << "Person::Fun1()" << endl; }virtual void Fun2() { cout << "person::Fun2()" << endl; }virtual void Fun3() final{ cout << "person::Fun3()" << endl; }//不能被重写virtual void Fun4() { cout << "person::Fun4()" << endl; }
};
class Student : public Person {
public://virtual void BuyTicket() { cout << "买票-半价" << endl; }/*注意:在重写基类虚函数时,派生类的虚函数在不加virtual关键字时,虽然也可以构成重写(因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范,不建议这样使用*/void BuyTicket() { cout << "买票-半价" << endl; }virtual void Fun1() { cout << "student::Fun1()" << endl; }virtual void Fun2() { cout << "student::Fun2()" << endl; }//virtual void Fun3() final { cout << "student::Fun3()" << endl; }virtual void Fun4() override{ cout << "student::Fun4()" << endl; }//virtual void Fun4(int x) override //{ cout << "student::Fun4()" << endl; }//报错//override检查是否重写,没有重写则报错
};int main()
{Person ps;Student st;ps.BuyTicket();ps.Fun1();ps.Fun2();ps.Fun3();ps.Fun4();cout << endl;st.BuyTicket();st.Fun1();st.Fun2();st.Fun3();st.Fun4();/*Func(ps);Func(st);*/return 0;
}