类中声明函数成员的时候,在函数的前面加上virtual
关键字,则该成员为虚函数
虚函数的特点
- 如果在类中定义的虚函数,那么系统会为这个类维护一个虚函数表
- 类中会多出4个字节的指针去指向这个虚函数表,在虚函数表中保存了虚函数的首地址,在调用虚函数的时候就会先到表中查找虚函数,然后调用,就比普通函数多了步操作
- 虚函数表不会被继承,但是表中的项会被继承(虚函数会被继承)
虚函数的作用
通过类的继承及虚函数来实现多态
- 有两个类,他们之间是父子关系
- 子类和父类有同名的虚函数,但是功能不同
- 父类指针或引用指向父类或子类对象,指向哪个对象就可以调用哪个对象的虚函数成员
示例:
#include<iostream>
using namespace std;class Animal {
public:virtual void speak() {cout << "动物在说话" << endl;}
};class Cat :public Animal {
public:virtual void speak() {//子类重写父类的虚函数cout<<"猫在喵喵叫" << endl;}
};
int main() {//调用:父类指针指向子类对象Animal* p = new Cat;p->speak();//调用的是Cat的speak()delete p;
}
多态下释放的注意事项
基类中有虚函数时,且通过父类指针去分配子类对象的时候,在释放的时候只能通过父类指针去进行释放,在delete父类指针的时候会调用父类的析构函数,而不会调用子类的析构函数;需要把父类的析构函数定义为虚析构,那么在释放父类指针的时候也就会调用子类的析构函数了。
以上面示例为例:
#include<iostream>
using namespace std;class Animal {
public:virtual ~Animal() {cout << "调用了父类析构" << endl;}virtual void speak() {cout << "动物在说话" << endl;}
};class Cat :public Animal {
public:~Cat() {cout << "调用了子类析构" << endl;}virtual void speak() {//子类重写父类的虚函数cout<<"猫在喵喵叫" << endl;}
};
int main() {//调用:父类指针指向子类对象Animal* p = new Cat;p->speak();//调用的是Cat的speak()delete p;
}
输出:
猫在喵喵叫
调用了子类析构
调用了父类析构
注意:构造函数不能是虚函数
纯虚函数
纯虚函数是一种特殊的虚函数。在基类中不能为虚函数给出有意义的实现,就可以把它声明为纯虚函数,然后把它的实现留给派生类去完成。
定义:virtual 函数返回值类型 函数名(函数参数)=0;
在C++中没有interface
关键字,“接口”的概念靠纯虚函数实现
示例:
#include<iostream>
#include<string>class Printable {
public:virtual std::string GetID() = 0;void PrintID() {std::cout << this->GetID() << std::endl;}
};class Student :public Printable {
public:std::string StuID = "S123456";std::string GetID() override {return StuID;}
};class Teacher :public Printable{
public:std::string TeaID = "T654321";std::string GetID() override {return TeaID;}
};int main() {Student stu;stu.PrintID();Teacher tea;tea.PrintID();
}
Student类和Teacher类可以看作是实现了“Printable接口”
纯虚析构
析构函数也可以声明成纯虚析构,类内写声明,不用实现;但要在类外实现。
virtual ~类名()=0;//纯虚析构的类内声明
类名::~类名(){};//纯虚析构的类外实现
抽象类
- 在一个类中具有一个及以上纯虚函数,那么这个类被称之为抽象类
- 抽象类不能实例化对象,但是可以定义指针,只能作为基类为派生类服务
- 如果派生类中没有完全实现基类中所有的纯虚函数,那么该派生类也会变成抽象类,同样不能实例化对象
final
- 可以阻止成员函数的重写:
virtual void fun() final
- 可以阻止类的继承:
class C1 final
注:一个抽象类被阻止继承,那么这个类就没有任何作用(一般不会这样写)