Tutorial Study Image

C++ 虚函数


2023年6月4日, Learn eTutorial
1066

C++ 是世界上使用最广泛的编程语言之一。它是 C 编程语言的扩展形式,并在一定程度上遵循面向对象编程 (OOP) 原则。C++ 甚至支持 OOP 的基本原理,包括封装、继承、多态等。在本教程中,您将重点关注 C++ 虚函数,因为它们对于多态性非常重要。

C++ 中虚函数是什么意思?

虚函数是指在基类中声明并在派生类中重新定义(覆盖)的成员函数。这意味着 C++ 中的虚函数是基类的一种成员函数,可以在派生类中重新定义以创建多态性。可以在基类中使用 virtual 关键字声明该函数。在基类中声明虚类后,您可以使用指针或引用调用虚类并运行派生类中该函数的虚版本。因此,它请求编译器创建函数绑定并在运行时确定对象的类型(后期绑定或动态链接)。

在 C++ 中,虚函数将始终确保使用引用或指针调用正确的函数。C++ 编程语言只允许使用单个指针来引用所有派生类的对象。由于指针包含对其派生自的所有对象的引用,因此将始终调用基类中的函数。此问题可以通过使用虚函数在 C++ 中解决,虚函数有助于在运行时执行派生类的虚版本。

当您使用指向基类的指针或引用来引用派生类对象时,可以为该对象调用虚函数并执行派生类中的函数版本。

虚函数的属性

  • 无论使用何种引用(或指针)来调用函数,虚函数都确保为对象调用正确的函数。
  • 它们的主要目的是实现运行时多态性。
  • 在基类中,函数使用 virtual 关键字声明
  • 运行时发生的函数调用解析。

规则 C++ 中虚函数有哪些规则?

以下是在 C++ 中创建虚函数时应遵循的一些准则。这些规则如下:

  • 虚函数绝不能是静态的。
  • 不同类的友元函数可以是虚函数。
  • 为了实现运行时多态性,应使用基类类型的指针或引用访问虚函数。
  • 虚函数在基类和派生类中应具有相同的原型。
  • 每次都在基类中定义并在派生类中覆盖。派生类不必覆盖(或重新定义)虚函数;在这种情况下,将使用基类中的函数定义。
  • 类中不允许虚构造函数,但允许虚析构函数。
  • 在基类中,函数使用 virtual 关键字声明。
  • 可以使用对象指针访问虚函数。

C++ 中虚函数的一个示例

该程序演示了虚函数的运行时行为。


#include<iostream>
using namespace std;

class base {
public:
 virtual void print()
 {
  cout << "Just print  the  base class\n";
 }

 void show()
 {
  cout << "Just show the base class\n";
 }
};

class derived : public base {
public:
 void print()
 {
  cout << "Just print the derived class\n";
 }

 void show()
 {
  cout << "Just show  the derived class\n";
 }
};

int main()
{
 base *bptr;
 derived d;
 bptr = &d;

 //The  Virtual function, binded at the runtime
 bptr->print();

 //The  Non-virtual function, binded at the compile time
 bptr->show();
 
 return 0;
}

 

输出


Just print the derived class
Just show the base class

程序解释

正如所解释的,创建运行时多态性的唯一方法是使用基类类型的指针(或引用)。基类指针也可以指向基类对象和派生类对象。上面代码中的基类指针“bptr”包含派生类对象“d”的地址。

由于 print() 函数用 virtual 关键字声明,它将在运行时绑定(输出打印派生类,因为指针指向其对象)。而 show() 是非虚的,它将在编译时绑定。

需要记住的一点:如果我们在基类中定义了一个虚函数并在派生类中覆盖了它,那么我们不需要在派生类中使用 virtual 关键字;因此,派生类中的函数将自动被视为虚函数。

虚函数中的 VTABLE 和 VPTR 概念

这里涵盖了 VTABLE 和 VPTA 概念。如果一个类有一个虚函数,编译器会执行两个操作。

  • 如果创建了该类的对象,则将一个指向该类 VTABLE 的虚指针 (VPTR) 添加为该类的数据成员。每次生成对象时,都会添加一个新的虚指针作为类的数据成员。
  • 无论是否生成对象,该类都带有一个名为 VTABLE 的成员,它是一个函数指针的静态数组。该表中存储了该类中每个虚函数的地址。
C++ Virtual Function

该程序展示了虚函数的工作原理


#include<iostream>
using namespace std;

class base {
public:
 void fun_1() { cout << "base-1\n"; }
 virtual void fun_2() { cout << "base-2\n"; }
 virtual void fun_3() { cout << "base-3\n"; }
 virtual void fun_4() { cout << "base-4\n"; }
};

class derived : public base {
public:
 void fun_1() { cout << "derived-1\n"; }
 void fun_2() { cout << "derived-2\n"; }
 void fun_4(int x) { cout << "derived-4\n"; }
};

int main()
{
 base *p;
 derived obj1;
 p = &obj1;

 // Early binding it is  becausethe  fun1() is non-virtual
 // in base
 p->fun_1();

 // Late binding (RTP)
 p->fun_2();

 // Late binding (RTP)
 p->fun_3();

 // Late binding (RTP)
 p->fun_4();

 // Early binding, however because the pointer is of base type and the function is of a derived class,
 //  the function call is illegal and results in an error.
 
 return 0;
}

 

输出


base-1
derived-2
base-3
base-4

程序解释

首先,我们建立一个基类指针并用派生类对象的地址对其进行初始化。当我们创建派生类对象时,编译器会创建一个指针作为类的数据成员,它包含派生类 VTABLE 的地址。

上面的示例使用了类似的后期绑定和早期绑定概念。当调用 fun1() 函数时,使用函数的基类版本;fun2() 在派生类中被覆盖,因此使用派生类版本;fun3() 在派生类中未被覆盖并且是虚函数,因此使用基类版本;fun4() 未被覆盖,因此使用基类版本。

C++ 中虚函数的编译时行为与运行时行为

  编译时行为 运行时行为

替代绑定

早期绑定

后期绑定

如何实现

指针类型

取决于指针指向的位置

C++ 纯虚函数是什么意思?

在 C++ 中,什么都不做的虚函数称为纯虚函数,也称为空操作函数。它只是用作占位符,不包含任何函数定义(空操作函数)。它在抽象基类中提及。这些类无法声明自己的任何对象。

以下语法用于在 C++ 中派生纯虚函数:


Virtual void class_name() = 0;
 

纯虚函数的示例程序


#include <iostream>

using namespace std;

class Base{

    public:

    virtual void Output() = 0;  

};

class Derived : public Base{

    public:

    void Output()  

    {

        std::cout << "The class which is derived from the Base class." << std::endl;

    }

};

int main(){

    Base *bpointr;

    Derived dpointr;

    bpointr = &dpointr;

    bpointr->Output();  

    return 0;

}

 

输出


The class which is derived from the Base class.

结论

在本教程中,您学习了 C++ 中的虚函数以及一些简单的示例。此外,您还了解了 C++ 纯虚函数是什么。

虚函数可以解决一个始终指向基类指针的问题。您可以访问我们的 C++ 教程,了解更多关于这些基本的 C++ 原则。这些课程旨在让您更轻松地理解不同的 C++ 编程主题和概念,并提高您的 C++ 开发技能。