【从 C 向 C++ 进阶】- 类 - 19. 虚函数

从 C 向 C++ 进阶系列导航


1. 函数重写

对于子类中与父类成员函数同名的成员函数,称其为子类的重写函数。函数重写一般发生在父类的成员函数不满足需求的情况下。

同时,父子类是相互兼容的:

  • 子类对象可以直接赋值给父类对象。
  • 子类对象可以直接初始化父类对象。
  • 父类指针可以指向子类对象。
  • 父类引用可以引用子类对象。
  • 子类可以当作父类使用。

但当使用父类类型的指针(或引用)调用子类的重写函数时,会发现实际调用的是父类中的同名函数。这是因为指针(或引用)是按照其所属类型即父类类型对对象进行解析的,并不清楚所指(或所引用)的对象究竟是属于子类类型还是父类类型。因此,不能使用父类指针(或引用)直接调用子类新加的成员函数。

  • 实验:
class Parent
{
public:
	void Print()
	{
		cout << "in Parent" << endl;
	}
};

class Child : public Parent
{
public:
	void Print()
	{
		cout << "in Child" << endl;
	}
	void Fun(){}
};

int main(int argc, char *argv[])
{	
	Child obj;
	obj.Print();		// in Child
	
	Parent* p = &obj;
	p->Print();			// in Parent
	// p->Fun();		// error: ‘class Parent’ has no member named ‘Fun’	
	
	Parent& ref = obj;
	ref.Print();		// in Parent
	// ref.Fun();		// error: ‘class Parent’ has no member named ‘Fun’
}

2. 虚函数

为了解决函数重写中带来的问题,C++ 提出了虚函数的概念,当成员函数定义为虚函数时,指针(或引用)会根据所指(或所引用)的实际对象调用其类型的成员函数。这便是大名鼎鼎的多态特性。

在父类中使用 virtual 关键字修饰成员函数便可以得到虚函数,在子类的重写函数中可以也使用 virtual 关键字进行修饰,也可以不显式修饰,编译器会自动把该函数认为为虚函数。但为了提高可读性,应在子类中也进行显式修饰。当子类发生函数重写时,必须在父类中把同名函数定义为虚函数。

  • 实验:
class Parent
{
public:
	virtual void vir_Print()
	{
		cout << "in Parent" << endl;
	}
	void Print()
	{
		cout << "in Parent" << endl;
	}
};

class Child : public Parent
{
public:
	virtual void vir_Print()
	{
		cout << "in Child" << endl;
	}
	void Print()
	{
		cout << "in Child" << endl;
	}
};

int main(int argc, char *argv[])
{	
	Parent parent_obj;	
	Child child_obj;
	
	Parent* p = &parent_obj;
	p->vir_Print();				// in Parent
	p->Print();					// in Parent

	p = &child_obj;
	p->vir_Print();				// in Child
	p->Print();					// in Parent	
	
	Parent& ref = child_obj;
	ref.vir_Print();			// in Child
	ref.Print();				// in Parent
}

对于虚函数的调用,称为动态联编,表示在程序实际运行后才能确定具体的函数调用。相应的,对于普通成员函数的调用,称为静态联编,表示在程序编译期间就能确定具体的函数调用。

发布了60 篇原创文章 · 获赞 36 · 访问量 5940

猜你喜欢

转载自blog.csdn.net/qq_35692077/article/details/97619855
今日推荐