C++ 中的虚函数和运行时多态 (polymorphism) - Virtual Functions and Runtime Polymorphism in C++

C++ 中的虚函数和运行时多态 (polymorphism) - Virtual Functions and Runtime Polymorphism in C++

The main thing to note about the program is that the derived class’s function is called using a base class pointer.
有关该程序的主要注意事项是使用基类指针调用派生类的函数。

The idea is that virtual functions are called according to the type of the object instance pointed to or referenced, not according to the type of the pointer or reference.
虚函数是根据指向或引用的对象实例的类型而不是根据指针或引用的类型来调用的。

In other words, virtual functions are resolved late, at runtime.
换句话说,虚拟函数在运行时被延迟解析。

//============================================================================
// Name        : function overriding
// Author      : Yongqiang Cheng
// Version     : Version 1.0.0
// Copyright   : Copyright (c) 2019 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>

using namespace std;

class Base
{
public:
	virtual void show()
	{
		cout << "In Base.\n";
	}
};

class Derived: public Base
{
public:
	void show()
	{
		cout << "In Derived.\n";
	}
};

int main(void)
{
	Base* bp = new Derived;
	Base bpt;
	Derived dpt;

	// RUN-TIME POLYMORPHISM
	bp->show();
	cout << endl;

	bpt.show();
	dpt.show();

	return 0;
}

In Derived.

In Base.
In Derived.

Virtual functions allow us to create a list of base class pointers and call methods of any of the derived classes without even knowing kind of derived class object.
虚函数使我们可以创建基类指针列表和任何派生类的调用方法,甚至无需知道派生类对象的类别。

Let the code has a simple base class Employee, the class contains virtual functions like raiseSalary(), transfer(), promote(), etc. Different types of employees like Manager, Engineer, etc. may have their own implementations of the virtual functions present in base class Employee.
让代码具有一个简单的基类 Employee,该类包含虚拟函数,例如 raiseSalary(), transfer(), promote(), etc. 不同类型的雇员,例如 Manager, Engineer 等,可能具有自己的虚拟函数实现 (存在于基类 Employee 中)。

In our complete software, we just need to pass a list of employees everywhere and call appropriate functions without even knowing the type of employee. For example, we can easily raise the salary of all employees by iterating through the list of employees. Every type of employee may have its own logic in its class, but we don’t need to worry about them because if raiseSalary() is present for a specific employee type, only that function would be called.
在我们完整的软件中,我们只需要在各处传递一个员工列表并调用适当的功能,甚至不需要知道员工的类型。例如,我们可以通过遍历员工列表轻松地提高所有员工的薪水。每种类型的员工可能在其类中都有自己的逻辑,但是我们不必担心它们,因为如果对于特定的员工类型存在 raiseSalary(),则只会调用该函数。

//============================================================================
// Name        : function overriding
// Author      : Yongqiang Cheng
// Version     : Version 1.0.0
// Copyright   : Copyright (c) 2019 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>

using namespace std;

class Employee
{
public:
	virtual void raiseSalary()
	{
		/* common raise salary code */
	}

	virtual void promote()
	{
		/* common promote code */
	}
};

class Manager: public Employee
{
	void raiseSalary()
	{
		/* Manager specific raise salary code, may contain increment of manager specific incentives*/
	}

	void promote()
	{
		/* Manager specific promote */
	}
};

// Similarly, there may be other types of employees.
// We need a very simple function to increment the salary of all employees.
// Note that emp[] is an array of pointers and actual pointed objects can be any type of employees.
// This function should ideally be in a class like Organization, we have made it global to keep things simple.
void globalRaiseSalary(Employee *emp[], int n)
{
	for (int i = 0; i < n; i++)
    {
		// Polymorphic Call: Calls raiseSalary()
		// according to the actual object, not according to the type of pointer
		emp[i]->raiseSalary();
	}
}

promote [prəˈməʊt]:vt. 促进,提升,推销,发扬 vi. 成为王后或其他大于卒的子
raise [reɪz]:vt. 提高,筹集,养育,升起,饲养,种植 vi. 上升 n. 高地,上升,加薪
incentive [ɪnˈsentɪv]:n. 动机,刺激 adj. 激励的,刺激的

Like globalRaiseSalary(), there can be many other operations that can be performed on a list of employees without even knowing the type of the object instance.
globalRaiseSalary() 一样,在不知道对象实例类型的情况下,可以对雇员列表执行许多其他操作。

Virtual functions are so useful that later languages like Java keep all methods as virtual by default.
虚函数是如此有用,以至于诸如 Java 之类的语言在默认情况下会将所有方法保持为虚方法。

在这里插入图片描述

The compiler maintains two things to serve this purpose:
编译器维护两件事来实现此目的:
vtable: A table of function pointers, maintained per class. (每个类维护的函数指针表。)
vptr: A pointer to vtable, maintained per object instance (see this for an example). (指向 vtable 的指针,针对每个对象实例进行维护 (请参见示例)。)

Compiler adds additional code at two places to maintain and use vptr. (编译器在两个地方添加了额外的代码来维护和使用 vptr。)
(1) Code in every constructor. This code sets the vptr of the object being created. This code sets vptr to point to the vtable of the class.
每个构造函数中的代码。此代码设置要创建的对象的 vptr。此代码将 vptr 设置为指向该类的 vtable

扫描二维码关注公众号,回复: 11172287 查看本文章

(2) Code with polymorphic function call (e.g. bp->show() in above code).
Wherever a polymorphic call is made, the compiler inserts code to first look for vptr using base class pointer or reference (In the above example, since pointed or referred object is of derived type, vptr of derived class is accessed). Once vptr is fetched, vtable of derived class can be accessed. Using vtable, address of derived derived class function show() is accessed and called.
具有多态函数调用的代码 (例如,上述代码中的 bp->show())。无论在何处进行多态调用,编译器都会插入代码以首先使用基类指针或引用查找 vptr (在上面的示例中,由于指向或引用的对象是派生类型,因此将访问派生类的 vptr)。 提取 vptr 后,即可访问派生类的 vtable。使用 vtable,可访问和调用派生派生类函数 show() 的地址。

The C++ standards do not mandate exactly how runtime polymorphism must be implemented, but compilers generally use minor variations on the same basic model.
C++ 标准没有明确规定必须如何实现运行时多态性,但是编译器通常在同一基本模型上使用较小的变体。

References

https://www.geeksforgeeks.org/c-plus-plus/

原创文章 532 获赞 1931 访问量 130万+

猜你喜欢

转载自blog.csdn.net/chengyq116/article/details/105258197
今日推荐