【C++】虚函数

发布于:2024-12-18 ⋅ 阅读:(88) ⋅ 点赞:(0)

类中声明函数成员的时候,在函数的前面加上virtual关键字,则该成员为虚函数

虚函数的特点

  1. 如果在类中定义的虚函数,那么系统会为这个类维护一个虚函数表
  2. 类中会多出4个字节的指针去指向这个虚函数表,在虚函数表中保存了虚函数的首地址,在调用虚函数的时候就会先到表中查找虚函数,然后调用,就比普通函数多了步操作
  3. 虚函数表不会被继承,但是表中的项会被继承(虚函数会被继承)

虚函数的作用

通过类的继承及虚函数来实现多态

  1. 有两个类,他们之间是父子关系
  2. 子类和父类有同名的虚函数,但是功能不同
  3. 父类指针或引用指向父类或子类对象,指向哪个对象就可以调用哪个对象的虚函数成员

示例:

#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;//纯虚析构的类内声明
类名::~类名(){};//纯虚析构的类外实现

抽象类

  1. 在一个类中具有一个及以上纯虚函数,那么这个类被称之为抽象类
  2. 抽象类不能实例化对象,但是可以定义指针,只能作为基类为派生类服务
  3. 如果派生类中没有完全实现基类中所有的纯虚函数,那么该派生类也会变成抽象类,同样不能实例化对象

final

  • 可以阻止成员函数的重写:virtual void fun() final
  • 可以阻止类的继承:class C1 final

注:一个抽象类被阻止继承,那么这个类就没有任何作用(一般不会这样写)


网站公告

今日签到

点亮在社区的每一天
去签到