2

也许更好的是:为什么标准在这些情况下需要转发到基类?(是的,是的 - 为什么? - 因为。)

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;

究竟,我在这里错过了什么?有人能想出一个场景来阐明标准中这种选择的“原因”吗?

4

1 回答 1

3

C++ 标准在 §10.3/2 中说:

成员查找规则 (10.2) 用于确定派生类范围内的虚函数的最终覆盖器,但忽略using-declarations引入的名称。

因此,即使您使用using B2::f;引入B2::f()派生类,也不会考虑覆盖B1::f().

因此,D2由于 §10.4/4 是抽象的:

一个类是抽象的,如果它包含或继承了至少一个最终覆盖器是纯虚拟的纯虚函数。

于 2010-05-29T02:32:43.377 回答