使用虚函数和重新定义的区别
Difference between using virtual functions and redefining
重定义虚函数和使用虚函数有什么区别?它们不是有相同的目的吗?你允许派生类的对象在两种情况下以相同的名称调用它们自己的函数版本..那么区别在哪里?
一个例子说明得很好:
#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
,对吗?
相关文章:
- 定义类模板构造函数的两种方法之间的区别
- 在类内和类外的定义处执行类转发声明是否有区别
- 定义带和不带INCLUDED_HEADERNAME_H的标头有什么区别
- 有没有办法声明一个公共静态常量,该常量将使用 constexpr 在源文件中定义(有什么区别)?
- 为什么相同的函数签名只有区别,另一个通过 const 获取参数是重新定义?
- 将类类型成员定义为公共和私有之间有什么区别?
- pimpl和定义类别的.cpp文件之间的区别
- 用户定义的类和标准类之间有区别吗?
- 两种类型的定义构造函数有什么区别?第一个使用":",第二个用大括号(如函数)定义它
- 未定义的行为和格式错误之间的区别,不需要诊断消息
- C++中变量的声明和定义之间有什么区别
- C++-CPP和H中定义的内联之间有什么区别
- 将函数定义为静态成员和自由成员之间有什么区别
- 定义 char 和 int 时指针有什么区别
- 当C++中都没有在基类中定义虚函数和纯虚函数时,虚拟函数和纯虚函数有什么区别
- 这两个类型定义有什么区别?
- RCDATA 和用户自定义资源有什么区别?
- 全局定义和范围内定义的区别
- 这两个高阶函数定义之间有什么区别吗?
- 在代码中定义字符串与控制台输入之间的区别