是否允许使用未使用的未定义方法?

时间:2014-11-07 22:45:04

标签: c++ language-lawyer virtual-functions undefined-function

这是一个带有未定义方法的类。似乎编译器允许构造此类的实例,只要从未调用未定义的成员函数:

struct A {
    void foo();
};

int main() {
    A a;      // <-- Works in both VC2013 and g++
    a.foo();  // <-- Error in both VC2013 and g++
}

这是类似的情况,但涉及继承。子类Bar扩展了基类FooFoo定义了一种方法g()Bar声明了同名的方法,但没有定义它:

#include <iostream>

struct Foo {
    void g() { std::cout << "g\n"; }
};

struct Bar : Foo {
    void g();
};

int main() {
    Bar b;      // Works in both VC2013 and g++
    b.Foo::g(); // Works in both VC2013 and g++
    b.g();      // Error in both VC2013 and g++
}

这是上述的变体。唯一的区别是g()virtualFoo Bar #include <iostream> struct Foo { virtual void g() { std::cout << "g\n"; } }; struct Bar : Foo { virtual void g(); }; int main() { Bar b; // Works in g++. But not in VC2013, which gives // 'fatal error LNK1120: 1 unresolved externals' b.Foo::g(); // Works in g++, but VC2013 already failed on b's construction b.g(); // Error in g++, but VC2013 already failed on b's construction }

virtual

请参阅代码注释,了解VC2013和g ++之间不同行为的对比。

  1. 哪个编译器是正确的,如果有的话?
  2. 为什么VC2013的编译器在其版本中使用virtual关键字与不包含Bar关键字的版本相比有不同的投诉?
  3. 是否始终允许使用未使用的未定义方法?如果不是,那么他们所处的所有情况都是如此 不允许?
  4. g()的{​​{1}}声明是否算作重写 即使Bar没有提供定义?

1 个答案:

答案 0 :(得分:8)

  

哪个编译器是正确的,如果有的话?

他们都是对的。您的代码错误,无需诊断。 [class.virtual] / 11

  

应定义或声明在类中声明的虚函数   纯粹(10.4)在该类中,或两者兼而有之;但不需要诊断   (3.2)。

[intro.compliance] / 2:

  

如果程序包含违反没有诊断规则的规则   要求,本国际标准不要求   关于该程序的实现。

查看GCC的优化设置,它们可能会影响行为。


  

是否始终允许使用未使用的未定义方法?

当且仅当使用了odr时,必须定义成员函数。 [basic.def.odr] / 3:

  

每个程序都应包含每个非内联的一个定义   在该程序中使用的函数或变量;没有诊断   必需的。

现在考虑[basic.def.odr] / 2:

  

表达式可能被评估,除非它是未评估的操作数(第5条)或其子表达式。
  [...]
  如果虚拟成员函数不纯,则使用它是有用的   一个非重载函数,其名称显示为可能已评估的表达式或一组候选函数的成员,如果从可能已评估的表达式引用时通过重载决策选择,则使用该函数,除非它是纯虚拟的函数及其名称未明确限定。

您仍然可以在decltypesizeof中使用未定义的非虚拟成员函数。但非纯粹的虚函数只是因为它们不纯粹而被使用。


  

即使在Bar,Bar的g()的声明也算作重写   没有提供定义?