讲一讲什么是多态:
1.多态的概念:同一个事物在不同场景下表现出不同的状态
举一个例子进行说明:
3.多态的实现条件 ---- 前提在继承的体系下
>>1.基类中必须要包含虚函数(被virtual关键字修饰的类成员函数成为虚函数),派生类中必须要对基类中的虚函数进行重写
>>2.虚函数的调用:必须通过基类的指针或引用调用虚函数
体现:在程序运行时,根据基类指针或引用对象的不同,从而实现多态。
class Person {
public:
virtual void BuyTicket() { cout << "买票-全价" << endl; }
};
class Student : public Person {
public:
virtual void BuyTicket() { cout << "买票-半价" << endl; }
/*注意:在重写基类虚函数时,派生类的虚函数在不加virtual关键字时,虽然也可以构成重写(因为继
承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范,不建议这样使用
*/
/*void BuyTicket() { cout << "买票-半价" << endl; }*/
};
void Func(Person& p)
{ p.BuyTicket(); }
int main()
{
Person ps;
Student st;
Func(ps);
Func(st);
return 0;
}
多态的体现:在程序运行时,来确定函数的行为(调用具体类的虚函数),在编译阶段,编译器只是简单检测语法是否有问题,此时编译器并不知道ps指向的是哪个类的对象,因此在编译阶段是不会确定函数的行为的。等待程序运行时,BuyTicker方法在调用时,才知道ps到底指向的是那个类型的对象,因此才会调用具体类的虚函数。
虚函数的重写:
虚函数的重写(也称为虚函数的的覆盖):派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型,函数名字,参数列表完全相同),称子类的虚函数重写了基类的虚函数。
1.派生类重写基类中的虚函数。
2.基类中的函数一定要是虚函数。
3.派生类虚函数的原型必须与基类虚函数的原型一致。
虚函数重写的两个例外:
1. 协变:(基类与派生类虚函数返回值类型不同)
派生类重写基类虚函数时,与基类虚函数返回值不同,即基类虚函数返回基类对象的指针或引用,派生类虚函数返回派生类队形的指针或引用,称为协变
class A{};
class B : public A {};
class Person {
public:
virtual A* f() {return new A;}
};
class Student : public Person {
public:
virtual B* f() {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指向的对象正确的调用析构函数。
int main()
{
Person* p1 = new Person;
Person* p2 = new Student;
delete p1;
delete p2;
return 0;
}