我们之前的继承 是派生类使用基类的方法 未作任何修改 如果我们希望一个方法在基类和派生类所表现的行为是不一样的,这种行为称为多态,和之前运算符重载一样
- 派生类重新定义基类的方法
- 使用虚方法
拿学生来做举例:说上课了,那么不同的学生可能会走进不同的教室,上课了,有的学生上语文课,有的学生上数学课,等等。所以针对同一个上课的消息,不同的学生产生的行为是不一样的。
方式1就不用介绍了,在派生类定义一个新的同名方法,然后调用它
方法2虚函数的核心思想是使用基类之指针,指向派生类的对象,调用虚函数的时候,最后调用的是派生类的函数
我们可以改写一下我们上节课定义的三个类,为他们添加一个shangke()的成员函数。
#pragma once
#include<iostream>
class Student
{
public:
int age;
unsigned int type;
Student(int agec = 0, int typec = 0) :age(agec), type(typec)
{
}
void shangke()
{
std::cout << "Student shangke()"<<std::endl;
}
};
class xiaostudent :public Student
{
public:
xiaostudent(int age = 0, int type = 1) :Student(age, type)
{
}
void shangke()
{
std::cout << "xiaostudent shangke()" << std::endl;
}
};
class chuxtudent :public Student
{
public:
chuxtudent(int age = 0, int type = 2) :Student(age, type)
{
}
void shangke()
{
std::cout << "chuxtudent shangke()" << std::endl;
}
};
class Bigxtudent :public Student
{
public:
Bigxtudent(int age = 0, int type = 3) :Student(age, type)
{
}
void shangke()
{
std::cout << "Bigxtudent shangke()" << std::endl;
}
};
C++运行结果
虽然用的是基类的指针 pStud 指向了派生类的对象,但是本身基类也有同名该函数,所以就调用了跟指针同类型的基类的 CStudent::shangke 的函数了;现在我们把基类中的成员函数shangke修改为virtual void shangke(); 这样就是一个虚函数了
我们现在再来运行一下程序
我们可以发现 两次调用的都是 CZhongStudent::shangke 函数。
虚函数的注意事项
- virtual 只能用来声明类的成员函数,把它作为虚函数,而不能将类作用域外的普通函数声明成虚函数。因为虚函数的作用是允许在派生类中对基类的虚函数重新定义。显然,他只能用于类的继承层次结构中;
- 一个类中的某个函数被声明成虚函数之后,同一类中就不能再定义一个非virtual的参数和返回值类型都相同的成员函数了。
虚函数的实际应用
很多人会说到比如逆向中的那些虚函数表等等 我们这里先不做介绍 ,因为目前是C++正向开发的笔记 - -
一般情况下是某个函数所在的类可能会作为父类/基类,而且该函数有可能会被派生类重写,并被派生类使用,那么这个时候就可以考虑将该函数声明为 virtual 虚函数。否则就不用!因为声明成虚函数之后是有开销的,所以不要随随便便的想声明成虚函数就声明。