文章目录
一、多态的概念和定义
前提: 这篇文章是在 vs2019下的 x86 程序中,涉及的指针都是4字节,如果在其他平台下,可能需要考虑指针8字节的问题等等。
1.1 多态的概念
- 完成某个行为时,不同的对象会产生不同的状态。比如买票,小孩有半价票,成人有成人票,退伍军人会免票,这就是多态的一个实际例子
- 多态是对继承进行扩展,即拥有了基类的一部分内容,又想在某些继承函数中添加独立的处理方式
1.2 多态的构成条件
前提:必须在继承的体系下
- 实现:基类函数必须是虚函数,子类必须对该虚函数进行"重写"
- 调用:通过基类对象的指针或者引用来调用虚函数
虚函数: 被virtual关键字修饰的类成员函数称为虚函数
多态的体现:
- 只有程序运行时才能体现出多态的性质,根据指针或者引用指向不同类的对象,从而调用对应的虚函数
- 编译阶段只进行语法检测,编译器并不知道指针指向哪一个类对象
二、虚函数的重写
2.1 重写规则
- 一定是派生类对基类的虚函数进行重写,如果基类中的不是虚函数则不能够成重写
- 派生类对虚函数重写,必须保证函数原型和基类中的一致,即:返回值,函数名,参数列表都要一样 (特例:析构函数和协变)
class A
{
public:
virtual void buy()
{
cout << "基类" << endl;
}
};
class B : public A
{
public:
virtual void buy()
{
cout << "派生类" << endl;
}
};
注意:派生类重写基类虚函数时,派生类不加 virtual 关键字也可以构成重写,因为基类中的虚函数被继承下来任然保持虚函数属性,但这样写不符合规范
2.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;}
};
析构函数:
只要基类对析构函数用virtual修饰,则派生类中的析构函数就形成了重写,虽然函数名不同,再编译器对析构函数的名称进行了特殊处理,编译之后析构函数名称同一处理为destructor
class A
{
public:
virtual ~A()
{
cout << "基类析构" << endl;
}
};
class B : public A
{
public:
~B()
{
cout << "派生类析构" << endl;
}
};
void Test()
{
A* a = new A;
A* b = new B;
delete a;
delete b;
}
注意事项:
- 如果派生类涉及内存管理,则基类中的析构函数必须用virtual修饰,否则可能造成内存泄漏。原因:基类指向动态开辟的派生类地址,delete 时如果基类中的析构不是虚函数(没有构成重写),派生类的资源将得不到释放
- 编译器会先调用派生类的析构函数,再调用基类的析构函数
- 重写之后,派生类虚函数和基类虚函数访问权限可以不同&#x