也许更好的是:为什么标准在这些情况下需要转发到基类?(是的,是的 - 为什么? - 因为。)
class B1 {
public:
virtual void f()=0;
};
class B2 {
public:
virtual void f(){}
};
class D : public B1,public B2{
};
class D2 : public B1,public B2{
public:
using B2::f;
};
class D3 : public B1,public B2{
public:
void f(){
B2::f();
}
};
D d;
D2 d2;
D3 d3;
女士给出:
sourceFile.cpp
sourceFile.cpp(24) : error C2259: 'D' : cannot instantiate abstract class
due to following members:
'void B1::f(void)' : is abstract
sourceFile.cpp(6) : see declaration of 'B1::f'
sourceFile.cpp(25) : error C2259: 'D2' : cannot instantiate abstract class
due to following members:
'void B1::f(void)' : is abstract
sourceFile.cpp(6) : see declaration of 'B
对于 MS 编译器也是如此。
我可能会买第一个箱子,D。但是在 D2 - f 是由 using 声明明确定义的,为什么编译器需要填写 vtable 还不够?
这种情况在标准中的什么地方定义?
添加以响应答案
关于我已接受的以下答案:
为什么这在规范中似乎不是错误?- 如果一个具有一系列非虚拟 f() 的继承层次结构,其在派生类中的使用由 using 语句确定,并且将基类中 f 的 decl 更改为虚拟,则可以更改哪个f 在派生类中调用 using 语句来选择它们的 f。这是一个我不知道的 c++“陷阱”。它可能是语言的一部分,但这种“远距离行动”让我感到不安,对我来说似乎违反了某种正确性/维护原则(我现在无法完全制定)。
但我可以举个例子:
#include <iostream>
using std::cout;
namespace NonVirtual_f{
class C0 {
public:
void f(){cout<<"C0::f()"<<'\n';}
};
class C1 : public C0{
public:
void f(){cout<<"C1::f()"<<'\n';}
};
class C2 : public virtual C1{
public:
void f(){cout<<"C2::f()"<<'\n';}
};
class D3 : public virtual C1, public C2{
public:
using C1::f;
};
}//namespace NonVirtual_f
namespace Virtual_f{
class C0 {
public:
virtual void f(){cout<<"C0::f()"<<'\n';}
};
class C1 : public C0{
public:
void f(){cout<<"C1::f()"<<'\n';}
};
class C2 : public virtual C1{
public:
void f(){cout<<"C2::f()"<<'\n';}
};
class D3 : public virtual C1, public C2{
public:
using C1::f;
};
}//namespace Virtual_f
int main(int argc,const char* const*argv){
NonVirtual_f::D3 nv3;
nv3.f();
Virtual_f::D3 v3;
v3.f();
return 0;
}
输出:
C1::f()
C2::f()
所改变的只是 C0 中 f 的虚性。特别是一旦选择了基类中 f 的非虚拟性,如果某个派生类(通常人们不知道)已经像上面的示例一样“被覆盖”,则无法在没有维护问题的情况下对其进行更改。
如果您反驳“好吧,不要在 NonVirtual 案例中以这种方式覆盖”,我同意这是不好的做法,但这似乎不仅如此。对我来说,语言应该:
不允许在 NonVirtual::D3 中使用(目前不可能,因为可能有其他重载的 f 要引入 [除非在函数情况下使用允许签名])
或者
完全禁止使用函数语句并强制转发
或者
在所有情况下都使用实际覆盖
或者
允许对函数(本质上是使用函数)进行一些语法声明,例如:
void f(*signature*) = C2::f;
究竟,我在这里错过了什么?有人能想出一个场景来阐明标准中这种选择的“原因”吗?