我刚刚创建了 2 个具有未定义行为的指针,并试图调用一个没有创建对象的类成员函数?
我不明白吗?
#include<iostream>
using namespace std;
class Animal
{
public:
void talk()
{
cout<<"I am an animal"<<endl;
}
};
class Dog : public Animal
{
public:
void talk()
{
cout<<"bark"<<endl;
}
};
int main()
{
Animal * a;
Dog * d;
d->talk();
a->talk();
}
最佳答案
A) 这是未定义的行为。任何行为都可能发生。
B) 因为您没有调用虚拟方法,所以很容易解释为什么未定义的行为实际上会这样做(而且我已经在我能找到的几乎所有编译器下测试了这一点)。
在 C++ 中,调用成员方法与调用带有隐藏“this”变量的成员是等价的(如果不是在定义中,实际上也是如此)。如果方法是虚拟的,它必须通过 vftable,但对于非虚拟方法则不需要。
所以
Foo::Bar(){}
大致相当于
Foo_Bar(Foo *this){}
在调用代码中
Foo *foo = new Foo();
foo->bar();
第二行大致相当于
Foo_Bar(foo);
现在,这里进行了一些简化,正如我所说,其中一些可能是实现细节而不是规范。但是,该行为是正确的(尽管依赖它是错误的)。
但是,鉴于前面的内容,请看一个实现:
void Foo::Bar(){printf("Hello, world!\n");}
和调用代码:
Foo *foo = 0;
foo->Bar();
正如我们所说,这大致等同于(因为我们是非虚拟的):
Foo *foo = 0;
Foo::Bar(foo);
这意味着我们正在调用以下方法的等价物:
void Foo_Bar(Foo* this)
{ printf("Hello, world\n"); }
现在,有了这个方法,我们实际上并没有取消 this 指针!因此,很清楚为什么在这种情况下该方法会起作用而不会失败。
这样做的实际结果是,在空指针上调用非虚拟方法(该方法不会取消引用 a 成员)通常会导致这种观察到的行为。但是,依赖任何未定义的行为基本上是邪恶的。
关于c++ - 下面的程序在 C++ 中如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2564952/