Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/google-app-engine/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么虚拟函数可以';如果分配了';新的';?_C++_Linker Errors_Language Lawyer_Virtual Functions - Fatal编程技术网

C++ 为什么虚拟函数可以';如果分配了';新的';?

C++ 为什么虚拟函数可以';如果分配了';新的';?,c++,linker-errors,language-lawyer,virtual-functions,C++,Linker Errors,Language Lawyer,Virtual Functions,因为malloc不调用(或者在本例中尝试调用)A的构造函数,而new调用 此代码编译并记录GCC中发生链接器错误的位置: undefined reference to `vtable for A' #包括 结构A { 虚拟void foo();//未使用且未实现 虚拟空栏(){} }; int main() { obj;//链接器错误 A*pm=(A*)malloc(sizeof(A));//确定 A*pn=newa;//链接器错误 } 即使虚拟函数“未使用”(因为它实际上由vtable使用)

因为malloc不调用(或者在本例中尝试调用)A的构造函数,而new调用

此代码编译并记录GCC中发生链接器错误的位置:

undefined reference to `vtable for A'
#包括
结构A
{
虚拟void foo();//未使用且未实现
虚拟空栏(){}
};
int main()
{
obj;//链接器错误
A*pm=(A*)malloc(sizeof(A));//确定
A*pn=newa;//链接器错误
}

即使虚拟函数“未使用”(因为它实际上由vtable使用),也不能让它未实现。这就是代码中的错误

由于编译器中vtables的一个特殊实现,这个bug以这种特殊的方式表现出来。您尚未实现第一个虚拟函数。每当编译器看到类的第一个虚拟函数的实现时,就会插入vtable。既然没有,就没有vtable

如果未实现第二个函数,链接器将抱怨该特定函数,而不是vtable

[编辑] 您的编译器可能优化了堆栈上的
a
副本,这就是链接器没有抱怨的原因


malloc
行实际上并不引用类型为A的对象,这就是为什么它不会产生链接器问题。但是,这一行还有另一个问题:它不应该编译<代码> MaloC/<代码>返回<代码>空洞*/COD>不转换为其他类型的指针,没有抛出。

< P>首先,此代码是不可编译的,因为在C++中,代码> VUL*<代码>不能隐式转换为<代码> A*<代码>。需要显式强制转换

其次,
malloc
的例子是完全不相关的
malloc
分配原始内存,与任何特定类型完全无关。在这种情况下,
malloc
知道任何
A
的注意事项,并且它不创建类型为
A
的对象

出于这个原因,这个问题的真实例子应该如下所示

#include <cstdlib>

struct A
{
  virtual void foo();  // unused and unimplemented
  virtual void bar () {}
};

int main ()
{
  A obj;        // linker error
  A* pm = (A*) malloc(sizeof(A)); // ok
  A* pn = new A; // linker error
}
问题是为什么第一个声明不会产生liker错误而第二个声明会产生liker错误

从形式上看,你的程序是无效的,因为它违反了C++语言(特别是ODR)的正式要求。实际上,两个声明都可能或应该产生相同的错误,因为在这两种情况下,对象形式上都需要指向VMT的指针。在这种情况下,无法创建VMT,因为某些函数未定义。然而,第一个声明只是因为编译器能够为第一个声明(而不是第二个声明)优化对VMT的所有引用而无法通过。编译器也很可能能够优化整个

obj
对象,因为它没有在其他任何地方引用

在GCC中(因为您似乎正在使用GCC),对于第一个声明也很容易触发相同的错误

struct A
{
  virtual void foo();  // unused and unimplemented
  virtual void bar () {}
};

int main ()
{
  A obj;        // ok
  A* pn = new A; // linker error
}
上述代码将在GCC中产生相同的链接器错误,即使未定义的函数
foo
仍未在此代码中使用


换句话说,只需添加足够数量的代码,使编译器相信需要对象的VMT。在这种情况下,声明之间的行为差异与C++语言无关。这只是特定于编译器的一个实现问题。

如果
A
是,则该标准只需要
A::foo
的一个实现 在程序中的任何地方实例化。无论 实例化是通过声明局部变量或通过 一个新的表达。但是,如果此规则不适用,则不需要诊断 破碎的如果您没有提供声明,或者您提供了两个或更多, 这只是未定义的行为。编译器所做的任何事情都是 “正确”。在这种情况下,可能发生的情况是:

  • 之所以需要该定义,是因为它在vtable中被引用
  • A
    的构造函数是内联的,因此初始化vptr(并触发vtable实例化)的代码对编译器是完全可见的

  • 由于对象的所有用途对编译器都是可见的,因此可以看到vptr从未被使用过,所以它只是将其取消

  • 如果没有vptr,则不需要生成vtable,因此没有对虚拟函数的引用

总之,这取决于编译器如何优化;你可能会出错 对于本地声明和新表达式,或者两者都不适用, 或者是为了一个而不是另一个。这可能取决于优化 选择,或者别的什么。就C++而言,它可能取决于 月亮的相位,而不是一个错误,你可以简单地得到 运行时崩溃的代码(但我首先说明的场景是
最有可能的是。)

不用功是无关紧要的。定义所有虚拟函数。就这么简单


您的自动存储持续时间对象(您选择称为“堆栈上”的对象)没有[多态性地]使用,因此您不会得到诊断。这并不正确。

我很震惊!如果它是在堆栈上分配的,就可以了?O.OStack分配也不起作用(“A obj;”),你确定这是“//ok”吗?这段代码是假的:如果不对
malloc
的结果进行显式强制转换,它将无法编译。我认为声明编译器优化标志很重要。使用-O4,gcc编译“一个obj;”而不是“新的一个”;使用-O0都会失败。@AndreyT:你一直把帖子和代码称为“假”,好像有人想欺骗你一样。“假”代码和“坏”代码是有区别的。@Neil Butterworth-Neil你回来了?堆栈分配还调用构造函数,因此这并不能解释为什么“A obj;”应该工作,而“new A”不应该工作。@Chris A.:codepad.org使用GCC,并且不会产生链接器错误
struct A
{
  virtual void foo();  // unused and unimplemented
  virtual void bar () {}
};

int main ()
{
  A obj;        // ok
  A* pn = new A; // linker error
}
struct A
{
  virtual void foo();  // unused and unimplemented
  virtual void bar () {}
};

int main ()
{
  A obj; // linker error
  A *p = &obj;
  p->bar(); 
}