首先,此代码不可编译,因为在 C++void *
中无法隐式转换为A *
. 需要显式转换。
其次,与 的例子malloc
完全无关。malloc
分配原始内存,与任何特定类型绝对无关。在这种情况下,malloc
知道注意 anyA
并且它不会创建类型的对象A
。
由于这个原因,这个问题的真实例子应该如下所示
struct A
{
virtual void foo(); // unused and unimplemented
virtual void bar () {}
};
int main ()
{
A obj; // ok
A* pn = new A; // linker error
}
问题是为什么第一个声明没有产生类似的错误,而第二个声明却产生了。
从形式的角度来看,您的程序是无效的,因为它违反了 C++ 语言的形式要求(特别是 ODR)。在实践中,两种声明都可能或应该产生相同的错误,因为在这两种情况下,对象都需要一个指向 VMT 的指针。在这种情况下,无法创建 VMT,因为某些函数未定义。但是,第一个声明只是因为编译器能够针对第一个声明(而不是第二个声明)优化所有对 VMT 的引用而忽略了。编译器也很可能能够优化整个obj
对象,因为它没有在其他任何地方引用。
在 GCC 中(因为您似乎在使用 GCC)很容易为第一个声明触发相同的错误
struct A
{
virtual void foo(); // unused and unimplemented
virtual void bar () {}
};
int main ()
{
A obj; // linker error
A *p = &obj;
p->bar();
}
上面的代码将在 GCC 中产生相同的链接器错误,即使foo
此代码中仍未使用未定义的函数。
换句话说,只需添加足够数量的代码,让编译器相信对象的 VMT 是需要的。在这种情况下,声明之间的行为差异与 C++ 语言无关。这只是特定于您的编译器的实现问题。