这是一个带有未定义方法的类。似乎编译器允许构造此类的实例,只要从未调用未定义的成员函数:
struct A {
void foo();
};
int main() {
A a; // <-- Works in both VC2013 and g++
a.foo(); // <-- Error in both VC2013 and g++
}
这是类似的情况,但涉及继承。子类Bar
扩展了基类Foo
。 Foo
定义了一种方法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()
与virtual
和Foo
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 ++之间不同行为的对比。
virtual
关键字与不包含Bar
关键字的版本相比有不同的投诉?g()
的{{1}}声明是否算作重写
即使Bar
没有提供定义?答案 0 :(得分:8)
哪个编译器是正确的,如果有的话?
他们都是对的。您的代码错误,无需诊断。 [class.virtual] / 11
应定义或声明在类中声明的虚函数 纯粹(10.4)在该类中,或两者兼而有之;但不需要诊断 (3.2)。
[intro.compliance] / 2:
如果程序包含违反没有诊断规则的规则 要求,本国际标准不要求 关于该程序的实现。
查看GCC的优化设置,它们可能会影响行为。
是否始终允许使用未使用的未定义方法?
当且仅当使用了odr时,必须定义成员函数。 [basic.def.odr] / 3:
每个程序都应包含每个非内联的一个定义 在该程序中使用的函数或变量;没有诊断 必需的。
现在考虑[basic.def.odr] / 2:
表达式可能被评估,除非它是未评估的操作数(第5条)或其子表达式。
[...]
如果虚拟成员函数不纯,则使用它是有用的 一个非重载函数,其名称显示为可能已评估的表达式或一组候选函数的成员,如果从可能已评估的表达式引用时通过重载决策选择,则使用该函数,除非它是纯虚拟的函数及其名称未明确限定。
您仍然可以在decltype
或sizeof
中使用未定义的非虚拟成员函数。但非纯粹的虚函数只是因为它们不纯粹而被使用。
即使在Bar,Bar的g()的声明也算作重写 没有提供定义?
是