C++ 虚函数

注:虚函数和虚继承是两个概念,解决的问题也不同;

虚函数:防止多重派生时,使用指针调用同名函数时以基类函数为准(非同名隐藏规则)

//使用virtual来达到同名隐藏规则的效果

B b(1, 2, 3, 4);
A0 *a;
a = &b;
a->Show();


//同名隐藏规则下的派生类函数直接输出自己的函数

虚继承(虚基类):解决“121”类二义性问题(防止在多重派生的基础上再次派生而产生二义性)

根据"赋值(父子)兼容规则":派生类可以作为父类使用,因为其继承了基类,但是基类不能够作为派生类使用;

在兼容规则下,使用派生类作为基类使用的时候,当遇到基类与派生类中存在同名的函数的时候,编译器会以以基类的函数为准,但是这不免有些使用不便;

为了产生:指定哪个类调用哪个类的函数的效果,于是产生了虚函数的概念;

1> 虚函数的理解

2> 虚函数的使用 (配合父子兼容规则)

3> 虚析构函数

4> 为什么要使用虚函数?

************************************************************************************************************************************

 

一:基本理解

什么是虚函数?

某基类中声明为virtual并在一个或多个派生类中重新定义的成员函数叫做虚函数;

虚函数有什么作用?

虚函数的作用是实现动态联编,也就是在函数运行阶段动态的选择合适的成员函数;

在定义了虚函数后,可以在派生类对虚函数进行重写,从而实现统一的接口,不同的执行过程。

在派生类中重写虚函数的时候,要保持重写的函数与原函数的一致性(包括返回值类型、参数个数与类型);

 

虚函数在定义的时候,基类结构中增加了一个虚函数指针表virtual table该表存放虚函数的调用地址,大小由虚函数个数决定,该表的首地址由基类内部指针vPtr指向。

C++ 虚函数_第1张图片

 如果继承类中存在同名的函数,则替换虚函数指针表中的相应同名函数,从而达到输出本类中的同名函数的效果。

C++ 虚函数_第2张图片

 

 

二:虚函数(举例)

 1> 首先举一个"父子兼容规则"的源码示例

#include 
using namespace std;

class A
{
private:

public:
	void Show() const
	{
		cout << "A0::Show" << endl;
	}
};

class A1 :public A
{
private:

public:
	void Show() const
	{
		cout << "A1::Show" << endl;
	}
};
class A2 :public A
{
private:

public:
	void Show() const
	{
		cout << "A2::Show" << endl;
	}
};

void Func(A &a)
{
	a.Show();
}

int main()
{
	A a;
	A1 a1;
	A2 a2;
	Func(a);
	Func(a1);
	Func(a2);
	return 0;
}

运行结果很明显:

 

2> 接下来给出使用虚函数后的源码以及运行结果:

源码:

#include 
using namespace std;

class A
{
private:

public:
	virtual void Show() const
	{
		cout << "A0::Show" << endl;
	}
};

class A1 :public A
{
private:

public:
	void Show() const
	{
		cout << "A1::Show" << endl;
	}
};
class A2 :public A
{
private:

public:
	void Show() const
	{
		cout << "A2::Show" << endl;
	}
};

void Func(A &a)
{
	a.Show();
}

int main()
{
	A a;
	A1 a1;
	A2 a2;
	Func(a);
	Func(a1);
	Func(a2);
	return 0;
}

<和上述代码相比仅仅加了一个virtual,当然也可以每个同名函数前都可以添加virtual函数,但是因为A1和A2是直接继承于A的,虚函数指针表 (Virtual Table)是可以被继承的,所以只要在基类中声明即可;>

C++ 虚函数_第3张图片

<如果派生类中继续派生,则在派生类中和派生类的派生类中对派生类中的同名函数使用virtual即可>

运行结果:

* 当然也可以对供调用的全局函数传入指针作为形参:

C++ 虚函数_第4张图片

* 上面的操作似乎已经完全ODK了,但是还有一个问题,就是"父子兼容规则"下析构韩函数的调用问题:

 

 

三:虚析构函数

1> 未使用虚析构函数:

#include 
using namespace std;

class A
{
public:
	 ~A()
	{
		cout << "A's destruct function!" << endl;
	}
};

class A1 :public A
{
public:
	~A1()
	{
		cout << "A1's destruct function!" << endl;
	}
};

void Func(A *a)
{
	delete a;
}

int main()
{
	A1 *a = new A1;
	Func(a);
	return 0;
}

 运行结果: 

 

2> 使用虚析构函数

#include 
using namespace std;

class A
{
public:
	virtual ~A()
	{
		cout << "A's destruct function!" << endl;
	}
};

class A1 :public A
{
public:
	~A1()
	{
		cout << "A1's destruct function!" << endl;
	}
};

void Func(A *a)
{
	delete a;
}

int main()
{
	A1 *a = new A1;
	Func(a);
	return 0;
}

运行结果:

C++ 虚函数_第5张图片

 

 

四:为什么要使用虚函数?

首先,如果想要显示派生类中的与基类中同名的函数,直接使用派生类实例化的对象直接调用不就可以了吗?

像这样:

C++ 虚函数_第6张图片

但是,条条大路通罗马,不同的解决方法会适用于不同的场景:

虚函数向我们提供了一种不使用实例化的对象通过“X.x()”的形式来显示函数的方法(虚函数是通过直接把实例化的对象作为参数传入一个单独的<公有显示函数>进行显示)。

 

 

 

 

 

 

 

你可能感兴趣的:(C++)