使用虚函数和重新定义的区别

Difference between using virtual functions and redefining

本文关键字:定义 区别 新定义 函数      更新时间:2023-10-16

重定义虚函数和使用虚函数有什么区别?它们不是有相同的目的吗?你允许派生类的对象在两种情况下以相同的名称调用它们自己的函数版本..那么区别在哪里?

一个例子说明得很好:

#include <iostream>
using namespace std;
class A {
public:
  virtual void f1() { cout << "Class A" << endl; }
  void f2() { cout << "Class A" << endl; }
  virtual ~A(){}
};
class B : public A {
public:
  virtual void f1() { cout << "Class B" << endl; }
  void f2() { cout << "Class B" << endl; }
  virtual ~B(){}
};
int main()
{
  A *a = new B;
  a->f1();
  a->f2();
}

$ ./override 
Class B
Class A

可以看到,当我们引用B的实例时,f1()仍然调用B的版本,而f2()调用A的版本。

当你声明一个虚函数时,你是在说,当我们调用它时,我们应该使用虚函数表来查找要调用的函数的正确版本,这样你总是会得到函数的最派生版本,即使你引用它作为一个祖先类型。如果没有virtual,它将简单地使用引用它的类型中的定义。

区别在于基类的引用或指针。调用虚函数将调用派生最多的版本,而调用普通函数将调用基类版本。

如果您直接使用变量或引用或指针指向最派生的类,则没有实际区别。

TL;DR

在c++中利用多态性的唯一方法是通过虚函数和指针(和引用)。当处理动态类型为子类的基类指针时,virtual关键字将告诉编译器在决定调用虚函数的哪个版本时,分配一个虚函数表查看。

多态如何在c++中工作

让我们举一个简单的例子:

class A { public: virtual void eat() { std::cout << "Class A" << std::endl; }
class B : public A {};
class C : public B { virtual void eat() { std::cout << "Class C" << std::endl; }

注意:在第一个函数/方法定义之后可以省略virtual关键字

:

A a; B b; C c;
A* ptrA = &a; A* ptrB = &b; A* ptrC = &c;
ptrA->eat();
ptrB->eat();
ptrC->eat();

将打印:

Class A
Class A
Class C

如果不将函数eat声明为虚函数,则输出将简单地为:

Class A
Class A
Class A

为什么

A* ptrA = &a; A* ptrB = &b; A* ptrC = &c;
不是

A* ptrA = &a; B* ptrB = &b; C* ptrC = &c;

在第二个版本中,eat()方法可以简单地为每个派生类重新定义,而不需要virtual,对吗?