为什么我们不能在编译时查找指向的对象类型?
Why can't we look up the type of an object pointed at at compile-time?
我试图用C++来理解虚函数。
struct B {
int f() { return 1;}
}
struct D : B {
int f() { return 1;}
}
在主函数中:
B* b = new D;
b.f()
我的理解是基类和派生类之间存在"竞争":它们都有一个具有相同名称和相同签名的函数。调用b.f()
时,只会选择其中一个。在虚拟案例中:
- 获胜者是根据 B 指向的物体类型选出 的
- 该选择是在运行时做出的
在非虚拟情况下:
- 获胜者是根据指针 B 的类型选择 的
- 该选择是在编译时做出的
我不明白两者之间的因果关系
-
virtual
关键字的使用 - 能够查找 B 所指向的对象类型
- 编译时与运行时
例如,为什么我们不能在编译时执行 (2)?
通常情况下,您无法在编译时知道类型。例如,考虑一个游戏,其中您有一些物理对象(实体),每个对象(实体)在接触时的行为可能不同。例如
struct Entity {
int x,y,w,h;
virtual void onPlayerContact() {}
};
struct ExitDoor : Entity {
void onPlayerContact() { exitLevel(); }
};
struct Monster : Entity {
void onPlayerContact() { diePlayer(); }
};
//...
现在,您将所有现有实体保留在一个大列表中,并在每一帧中浏览列表,检查您的播放器是否与该实体有联系,如果是,则调用onPlayerContact
。 即:
static std::set<Entity*> entities;
static Player* player;
void frame() {
for(Entity* entity : entities) {
if(player->contacts(entity))
entity->onPlayerContact(); // it's only known at runtime what to call here
}
}
这是一个简单的例子
void some_function(B* b)
{
b.f();
}
int main()
{
int i;
cin >> i;
if (i == 0)
{
B *b = new B();
some_function(b);
}
else
{
D *d = new D();
some_function(d);
}
return 0;
}
在编译时,您不知道传递给函数"some_function(B* b)"的对象的确切类型。它应该在运行时决定。
你可以做 (2),只要你做 (1),使用 virtual
.你做 (2) 与typeid
.一般来说,这不是性能最高的方法。(反馈效应:它很少有用,所以很少优化,这使得它更少使用,等等)。
依赖关系的原因是virtual
启用了 RTTI(运行时类型信息),这也是 2 所必需的。RTTI的一种常见形式是所谓的vtable
,它是一个包含指向给定类的虚函数的指针的表。每个具有虚函数的对象都有一个指向此表的指针。可以通过几种方式将typeid
信息添加到此类表中(嵌入、数据指针、指向返回它的函数的指针等)。但是除了指向vtable
的指针之外,还有其他选项可以实现RTTI,所以不要认为这是唯一的方法。
您还想知道为什么不能在运行时执行此操作。考虑以下代码
void Foo(std::ostream&);
int main(int argc, char **argv)
{
if (argc == 2)
{
std::ofstream outFile(argv[1]);
Foo(outFile);
}
else
{
Foo(std::cout);
}
}
显然,在编译Foo
时,您不知道在运行时会得到什么。这取决于命令行。在编译时,你只知道你会得到一个ostream&
。
- 在 C++ 中将一个模板类型的对象类型转换为另一个模板类型
- 了解 Python 中的对象类型
- 具有纯虚函数和指针数组对象类型的父类的指针数组
- 调用的对象类型 'double' 不是 report() 函数的函数或函数指针
- 基准、值、值类型、对象和对象类型(C++)
- JNI 如何将 Java 对象数组传递给相同对象类型的 C++ 数组
- 在构造过程中更改的对象类型
- 如何构建程序以避免查询对象类型?
- 如何使用Dynamic_cast获得对象类型
- 什么更有效率?在重载函数中或通过在基类函数中检查对象类型来实现
- static_cast实际上不是对象类型的类型是未定义的行为吗?
- 为什么 std::variant 不能容纳数组对象类型,而联合可以?
- 为什么类型转换对象不会更改其地址?有关对象类型的信息存储在哪里?
- 类返回对象类型,但如何返回和检查 null
- 是否可以在辅助功能中概括对象类型
- 表达式必须在C 中具有指针对象类型
- 下标需要数组或指针类型表达式必须具有指针对象类型
- 当将对象传递给具有参数作为引用类型的函数以及当其类对象类型时,会得到不同的输出
- 如何在运行时指定对象类型
- 我可以获取在重载的新运算符中使用新运算符的对象类型吗?