我创建了两个类,A和B. B包含一个指向A的指针,但从不初始化A.但是,我可以在不初始化A的情况下调用A的函数。如何/为什么这可能?
class A
{
public:
void Test() {
printf("Test from A\n");
}
};
class B
{
public:
B() {
}
~B() {
}
void T() {
a->Test();
}
private:
A* a;
};
int main() {
B b;
b.T();
/*
B* b;
b->T(); //This does not work, as expected. So why can I call a->Test via b.T(), and have that work when a was never initialized?
*/
system("PAUSE");
return 0;
}
答案 0 :(得分:1)
这是因为编译器在内部将a-> Test()之类的调用转换为稍微不同的形式:
A::Test(a);
正如你所看到的,它调用的函数只是一个地址,它被调用的对象作为参数传递,可以是nullptr / uninitialized / anything。
对于虚拟功能,它将几乎相同,涉及更多细节:
a->vtbl[0](a);
其中vtbl是一个虚函数指针表,通常在对象构造时初始化,但它的偏移量通常在编译时就已知,这就是为什么编译器实际上没有任何麻烦“调用”它的对象不存在 - 它只会从随机存储器位置读取垃圾并快乐地使用它。
答案 1 :(得分:0)
虽然a *的值未定义,但我相信实际定义了此代码的行为。
测试功能的真实标题将生成为:
void Test(A* this);
含义 - 它是一个简单的C函数,它将结构的指针作为其第一个参数。
由于你的b对象中有一个初始化的对象(由它指向的内存中的任何驻留随机初始化),当你调用a-> test()时,你将正确调用Test函数(使用相同的函数)随机作为"这个")的值。由于你没有使用"这个"在Test中,它实际上会按预期工作。