c++多态
2022-11-23 本文已影响0人
arkliu
多态的基本概念
- 基类指针只能调用基类的成员函数,不能调用派生类的成员函数
#include <iostream>
#include<string>
using namespace std;
class Parent{
public:
int m_id = 0;
void show() {
cout <<"Parent::show() m_id:"<<m_id<<endl;
}
};
class Child:public Parent {
public:
int m_age;
void show() {
cout <<"Child::show() m_id:"<<m_id << " m_age:"<<m_age<<endl;
}
};
int main() {
Child ch;
ch.m_id = 10;
ch.m_age = 20;
Parent *par = &ch;
par->show(); // 基类指针指向派生类对象,调用基类的函数
return 0;
}
![](https://img.haomeiwen.com/i13167756/1701f0579210c3e5.png)
- 如果在基类的成员函数前加上virtual关键字,把他声明为虚函数,基类指针就可
以调用派生类的成员函数。
class Parent{
public:
int m_id = 0;
// 在基类的show方法前加上virtual关键字,声明为虚函数
virtual void show() {
cout <<"Parent::show() m_id:"<<m_id<<endl;
}
};
![](https://img.haomeiwen.com/i13167756/a8c9f1c68361da85.png)
- 有了虚函数,基类指针指向基类对象就使用基类成员函数和基类的数据,指向派生类对象时,就使用派生类对象的成员函数,和派生类的数据
#include <iostream>
#include<string>
using namespace std;
class Parent{
public:
int m_id = 0;
// 在基类的show方法前加上virtual关键字,声明为虚函数
virtual void show() {
cout <<"Parent::show() m_id:"<<m_id<<endl;
}
};
class Child:public Parent {
public:
int m_age;
void show() {
cout <<"Child::show() m_id:"<<m_id << " m_age:"<<m_age<<endl;
}
};
int main() {
Child ch;
ch.m_id = 10; ch.m_age = 20; //创建派生类对象并赋值
Parent par;
par.m_id = 33;
Parent *ppar = &ch;
ppar->show(); // Child::show() m_id:10 m_age:20
ppar = ∥
ppar->show(); // Parent::show() m_id:33
return 0;
}
![](https://img.haomeiwen.com/i13167756/825a8e96f1cef7c8.png)
- 只需要在基类的函数声明中加上virtual关键字,函数定义时不能加。
class Parent{
public:
int m_id = 0;
// 在基类的show方法前加上virtual关键字,声明为虚函数
virtual void show();
};
void Parent::show() {
cout <<"Parent::show() m_id:"<<m_id<<endl;
}
- 当在基类中定义类虚函数时候,如果派生类没有定义该函数,那么将使用基类的虚函数。
- 在派生类中重定义了虚函数的情况下,如果要使用基类的函数,可以加类名和域解析符。
Child ch;
ch.m_id = 10; ch.m_age = 20; //创建派生类对象并赋值
Parent par;
par.m_id = 33;
Parent *ppar = &ch;
ppar->Parent::show(); // Parent::show() m_id:33
![](https://img.haomeiwen.com/i13167756/71026019f9dccfad.png)
虚析构函数
有时会让一个基类指针指向用 new 运算符动态生成的派生类对象;同时,用 new 运算符动态生成的对象都是通过 delete 指向它的指针来释放的。如果一个基类指针指向用 new 运算符动态生成的派生类对象,而释放该对象时是通过释放该基类指针来完成的,就会导致少释放一次, 看下面案例:
virtual_deconstruct.h
#pragma once
#include <iostream>
using namespace std;
class Parent
{
private:
public:
Parent();
~Parent();
};
Parent::Parent()
{
cout << "Parent() runs.." << endl;
}
Parent::~Parent()
{
cout << "~Parent() runs.." << endl;
}
class Child : public Parent
{
private:
public:
Child();
~Child();
};
Child::Child()
{
cout << "Child() runs.." << endl;
}
Child::~Child()
{
cout << "~Child() runs.." << endl;
}
测试代码
#include <iostream>
#include "virtual_deconstruct.h"
using namespace std;
int main() {
Parent * p = new Child();
delete p;
return 0;
}
![](https://img.haomeiwen.com/i13167756/c994b913790439e4.png)
输出结果说明,,没有引发 Child类的析构函数被调用。这是因为该语句是静态联编的,编译器编译到此时,不可能知道此时 p 到底指向哪个类型的对象,它只根据 p 的类型是 Parent* 来决定应该调用 Parent类的析构函数。
按理说,delete p;会导致一个 Child类的对象消亡,应该调用 Child类的析构函数才符合逻辑,否则有可能引发程序的问题
解决
更改改写上面程序中的 Parent类,在析构函数前加 virtual 关键字,将其声明为虚函数:
class Parent
{
private:
public:
Parent();
virtual ~Parent();
};
此时运行结果如下:
![](https://img.haomeiwen.com/i13167756/9e74b2cb1974e2ba.png)