Cod*_*cks 8 c++ virtual-functions language-lawyer undefined-function
这是一个带有未定义方法的类.似乎编译器允许构造此类的实例,只要从未调用未定义的成员函数:
struct A {
void foo();
};
int main() {
A a; // <-- Works in both VC2013 and g++
a.foo(); // <-- Error in both VC2013 and g++
}
Run Code Online (Sandbox Code Playgroud)
这是一个类似的情况,但涉及继承.子类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++
}
Run Code Online (Sandbox Code Playgroud)
这是上面的变化.这里唯一的区别是,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
}
Run Code Online (Sandbox Code Playgroud)
有关VC2013和g ++之间不同行为的对比,请参阅代码注释.
virtual
关键字与没有virtual
关键字的版本相比有一些不同的投诉呢?Bar
的的申报g()
数作为压倒一切的,即使Bar
不提供一个定义?哪个编译器是正确的,如果有的话?
他们都是对的.您的代码错误,无需诊断.[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()的声明是否算作重写?
是.