C++ 学习笔记(二) 多态的实现

前几天面试的时候被问到了多态的实现,平时确实没有用到过。今天特意去看了相关的知识,并实现了一下,来看一看输出结果,并分析一下导致这样的结果的原因。

#include "stdafx.h"
#include<iostream>
using namespace std;

class Father
{
public:
	virtual void TestV()
	{
		cout << "father.virtual test" << endl;
	}

	void Test()
	{
		cout << "father.normal test" << endl;
	}
};

class Son1:public Father
{
	void TestV()
	{
		cout << "son1.virtual test" << endl;
	}
	void Test()
	{
		cout << "son1.normal test" << endl;
	}
};
class Son2 :public Father
{
	void TestV()
	{
		cout << "son2.virtual test" << endl;
	}
	void Test()
	{
		cout << "son2.normal test" << endl;
	}
};
int _tmain(int argc, _TCHAR* argv[])
{
	Son1 son1;
	Son2 son2;

	Father *pf1 = &son1;
	Father *pf2 = &son2;

	pf1->TestV();
	pf2->Test();

	return 0;
}

Father *pf = &son;这样的语句我本来以为是定义了一个父类对象指针,指向子类对象,所以这个pf应该是一个Son的对象,所以在调用Test方法时,应该是调用子类的方法。 结果如下:


但事实上,只有TestV()这个方法,这个重写了父类的虚函数的方法是调用到了子类的方法,而普通的Test()方法,确是调用的父类的方法。

这就说明,这个virtual关键字,确实起到了他的作用。(废话),这里为什么结果会这样,已经不是我能够想清楚的了。参考另一篇博客的内容就能理解了。

点击打开链接

这里涉及到了两个概念:早绑定,晚绑定

早绑定:C++编译器在编译的时候,需要确定每一个对象调用的函数(非虚函数)的地址。Father *pf = &son;通过这个语句,我们把Son类的对象son的地址赋值给力pf时,C++编译器进行了隐式的类型转换,编译器就认为pf保存的是Father对象的地址,所以调用的就是Father对象的函数。但实际上,pf指向的是Son类的对象,希望输出的是Son类的方法,这个时候就要用到虚函数,采用晚绑定来实现了。

晚绑定:在基类中声明函数时使用virtual关键字来告诉编译器进行晚绑定。即不在编译阶段确定对象调用函数的地址,而是在运行时再去确定对象的类型以及正确的调用子类的函数。

这里面还涉及到了虚表,虚表指针

编译器会为每一个包含虚函数的类创建一个虚表(一维数组),存放虚函数的地址。为每个对象提供了一个虚表指针,指向该对象所属类的虚表。在程序运行时,根据对象类型去初始化虚表指针,从而让虚表指针指向了所属类的续表,从而在调用虚函数的时候,能够找到正确的函数。虚表的创建和虚表指针的初始化是在构造函数中进行的。

猜你喜欢

转载自blog.csdn.net/u011310341/article/details/79438694