我正在学习 C++,我刚刚进入虚拟函数。
从我读到的(在书中和在线)中,虚函数是基类中的函数,您可以在派生类中覆盖它们。
但是在本书的前面,在学习基本继承时,我能够在不使用 virtual
的情况下覆盖派生类中的基函数。
那么我在这里错过了什么?我知道虚函数还有更多,而且它似乎很重要,所以我想弄清楚它到底是什么。我只是无法在网上找到一个简单的答案。
原文由 Jake Wilson 发布,翻译遵循 CC BY-SA 4.0 许可协议
我正在学习 C++,我刚刚进入虚拟函数。
从我读到的(在书中和在线)中,虚函数是基类中的函数,您可以在派生类中覆盖它们。
但是在本书的前面,在学习基本继承时,我能够在不使用 virtual
的情况下覆盖派生类中的基函数。
那么我在这里错过了什么?我知道虚函数还有更多,而且它似乎很重要,所以我想弄清楚它到底是什么。我只是无法在网上找到一个简单的答案。
原文由 Jake Wilson 发布,翻译遵循 CC BY-SA 4.0 许可协议
跟进@user6359267 的回答,C++ 范围层次结构是
global -> namespace -> class -> local -> statement
因此,每个类都定义了一个范围。如果不是这种情况,子类中的重写函数实际上将重新定义同一范围内的函数,这是链接器不允许的:
由于每个类都定义了自己的范围,因此被调用的函数是在调用该函数的对象的类中定义的函数。所以,
#include <iostream>
#include <string>
class Parent
{
public:
std::string GetName() { return "Parent"; }
};
class Child : public Parent
{
public:
std:::string GetName() { return "Child"; }
};
int main()
{
Parent* parent = new Parent();
std::cout << parent->GetName() << std::endl;
Child* child = new Child();
std::cout << child->GetName() << std::endl;
*parent = child;
std::cout << child->GetName() << std::endl;
return 0;
}
输出
Parent
Child
Parent
因此,我们需要一种方法来告诉编译器要调用的函数应该在运行时而不是编译时确定。这就是 virtual 关键字的作用。
这就是为什么函数重载被称为编译时多态性(或早期绑定)而虚函数覆盖被称为运行时多态性(或后期绑定)的原因。
细节:
在内部,当编译器看到一个虚函数时,它会创建一个类成员指针,该指针通常使用 .*
指向类的成员(而不是对象中该成员的特定实例)和 ->*
运营商。他们的工作是允许您访问给定指向该成员的指针的类的成员。这些很少被程序员直接使用(也许除非你正在编写一个编译器来实现“虚拟”)。
原文由 A. Hendry 发布,翻译遵循 CC BY-SA 4.0 许可协议
3 回答2k 阅读✓ 已解决
2 回答3.9k 阅读✓ 已解决
2 回答3.2k 阅读✓ 已解决
1 回答3.2k 阅读✓ 已解决
1 回答2.7k 阅读✓ 已解决
3 回答3.4k 阅读
1 回答1.6k 阅读✓ 已解决
没有“虚拟”,您将获得“早期绑定”。使用该方法的哪个实现在编译时根据您调用的指针的类型来决定。
使用“虚拟”,您将获得“后期绑定”。使用该方法的哪个实现在运行时根据所指向对象的类型来决定——它最初被构造为什么。根据指向该对象的指针的类型,这不一定是您所想的。
编辑- 看到 这个问题。
此外 - 本教程 涵盖 C++ 中的早期和后期绑定。