虚函数,虚析构函数,纯虚函数

虚函数

虚函数:虚函数是运行时多态,若某个基类函数声明为虚函数,则其公有派生类将定义与其基类虚函数原型相同的函数。那么,当基类指针或基类引用操作派生类对象时,系统会自动用派生类中的同名函数代替基类虚函数

基类定义虚函数后,将会一 虚到底——派生类里的同名函数也为虚函数

虚函数前提:

(1)基类,派生类中拥有原型相同的成员函数

(2)通过virtual关键字,将virtual关键字放在函数前面可将该函数定义为虚函数

通过基类指针指向派生类对象时,调用同名函数时,如果该函数不是虚函数,函数的调用取决于左侧变量的类型;如果该函数时虚函数,函数的调用取决于对象的类型;

如下面这个实例:

#include<iostream>
using namespace std;
class Animal		//定义基类
{
public:
	//定义speak函数
	 void speak() {
		cout << "Animal language" << endl;
	}
};
class Cat :public Animal		//定义派生类,且继承
{
public:
	//定义speak函数
	 void speak() {
		cout << "cat language  miao miao" << endl;
	}
};

class Dog
{
public:
	void speak() {
		cout << "Dog language  wang wang" << endl;
	}
};
int main()
{
	Cat cat;//定义派生类对象
	cat.speak();//通过派生类调用speak函数
	Animal *panimal = &cat;//定义基类指针指向子类对象
	panimal->speak();
	Dog dog;
	dog.speak();
	system("pause");
	return 0;
}

运行结果:

 运行结果:当基类指针指向派生类类对象的时候,调用speak()函数的时候,调用的是基类的函数,这个时候不是虚函数。

当在基类和派生类的speak()函数前加上virtual关键字的时候,再运行代码试试:

加上virtual关键字后,基类指针指向了派生类对象,调用speak()函数的时候,调用的就是派生类的函数了。

这个时候,我们之前这些只是虚函数表面的东西,现在我们在讲讲为什么通过定义虚函数,基类指针就可以直接调用派生类函数了。

虚函数原理

虚函数通过动态联编实现了运行时多态,编译器在执行过程中遇到了virtual关键字,会为这些虚函数的类建立一张虚函数表vtable

在虚函数表中,编译器将按照该虚函数的声明顺序依次保存虚函数地址,同时在每个带有虚函数的类中放置vptr指针,用来指向虚函数表

如图所示:

该图只是一个类的虚函数表,下面我们通过一段代码,来分析他的虚函数表;

class Animal {//基类
public:
	//虚函数speak
	virtual void speak() { cout << "animal language!" << endl; }
	//虚函数sleep
	virtual void sleep() { cout << "animal sleep!" << endl; }
};

class Cat :public Animal {
public:
	//虚函数 cat_speak
	virtual void cat_speak() { cout << "cat language : miao maio" << endl; }
	//虚函数cat_sleep
	virtual void cat_sleep() { cout << "cat sleep!" << endl; }
};

上述代码中,基类和派生类分别有两个虚函数,且基类和派生类中虚函数名称不同,现在分析上述代码的虚函数表:

 这是上述代码的虚函数表,现在我们修改上述代码

class Cat :public Animal {
public:
	//虚函数 speak
	virtual void speak() { cout << "cat language : miao maio" << endl; }
	//虚函数cat_sleep
	virtual void cat_sleep() { cout << "cat sleep!" << endl; }
};

将cat_speak()函数修改与基类同名,这个时候我们再来看看虚函数表:

 从该表中,我们知道了,当基类和派生类有同名虚函数的时候,派生类中的虚函数会将基类的虚函数从虚函数表中替换掉。因此我们可以通过基类指针指向派生类对象时,通过基类指针获取到派生类的选函数。

虚析构函数

在C++中,不能声明虚构造函数,可声明虚析构函数,虚析构函数是为了解决基类指针指向派生类对象,并用基类的指针销毁派生类对象的应用产生的。

通常基类指针指向一个new生成的派生对象,通过delete销毁基类指针指向的派生类对象时,会出现两种情况;

(1)如果基类析构函数不是虚析构函数,则只会调用基类的析构函数,派生类的析构函数不被调用,此时派生类中申请的资源不被回收

(2)如果基类中的析构函数是虚析构函数,则释放基类指针指向的对象时会调用基类及派生类析构函数,派生类对象中的所有资源被回收。

纯虚函数

在定义一个表示抽象概念的基类时,有时无法或者不需要给出某些成员函数的具体实现,函数的实现在派生类中完成,基类中这样的函数声明为纯虚函数。

纯虚函数没有函数体,其作用实在基类中为派生类保留一个函数接口,方便派生类根据需要对它实现,实现多态。

纯虚函数声明结构

virtual 函数返回值类型 函数名(参数表) = 0;

纯虚函数没有函数体,纯虚函数不可被调用,声明格式后面的"= 0"是以这样的形式说明该函数为纯虚函数。

有兴趣可看一下以下代码

#include<iostream>
using namespace std;
class Animal		//定义基类
{
public:
	//定义speak函数
	virtual void speak() = 0;//定义纯虚函数
};
class Cat :public Animal		//定义派生类,且继承
{
public:
	//定义speak函数
	virtual void speak() {
		cout << "cat language  miao miao" << endl;
	}
};

class Dog
{
public:
	virtual void speak() {
		cout << "Dog language  wang wang" << endl;
	}
};
int main()
{
	Cat cat;//定义派生类对象
	cat.speak();//通过派生类调用speak函数
	//cat.Animal::speak();//调用基类同名函数
	Dog dog;
	dog.speak();
	system("pause");
	return 0;
}


版权声明:本文为qq_49190652原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。