隐藏私有的重载虚拟功能?

时间:2017-07-05 14:52:49

标签: c++ inheritance g++ clang++

我有一个类似于以下的类层次结构:

class A 
{ 
protected: 
    virtual void f(int) = 0;
};

class B 
{ 
protected: 
    virtual void f(char*) = 0;
};

class DA : A 
{ 
private:
    virtual void f(int) override {}
};

class DB : public DA, B 
{ 
private:
    virtual void f(char*) override {}
};

当我尝试使用clang(或gcc)进行编译时,它会给我警告

<source>:22:18: warning: 'DB::f' hides overloaded virtual function [-Woverloaded-virtual]
    virtual void f(char*) override {}
                 ^
<source>:16:18: note: hidden overloaded virtual function 'DA::f' declared here: type mismatch at 1st parameter ('int' vs 'char *')
    virtual void f(int) override {}
                 ^

我明白了,但它真的应该发出警告吗?毕竟,DB甚至看不到隐藏的功能(甚至可能巧合地命名相同)。

如果它不是私密的,我可以使用

using DA::f;

当然要澄清,但功能是私密的,DB甚至不知道它,当然也不应该暴露它。

有没有办法在不停用该警告的情况下修复此问题,即告诉编译器所有内容都按预期设计?

3 个答案:

答案 0 :(得分:3)

  

毕竟,DB甚至看不到隐藏的功能(甚至可能巧合地命名相同)。

可访问性和可见性是C ++中的不同概念。默认情况下,DA::f()DB可见(然后由DB::f()隐藏),但它无法访问,因为它在DA内是私有的,DB不是DA的朋友。有人可能会争辩说隐藏一个无法访问的功能是无害的,因为无论如何都无法调用它。但是,隐藏和不可访问之间的区别可能很大,因为可见和不可访问的功能确实参与了重载决策。如果dbDB类型的对象,那么db.f(0)会做什么?如果DA::f()可见但不可访问,则会将其选为最佳匹配项,编译器将发出诊断信息,因为它无法访问,因此无法调用。但是,如果隐藏了DA::f(),编译器将选择接受指针的重载,并将文字0视为空指针。

答案 1 :(得分:0)

我最终做的(现在)是使用合成而不是私有继承。所以我的代码目前看起来像

class A 
{ 
protected: 
    virtual void f(int) = 0;
};

class B 
{ 
protected: 
    virtual void f(char*) = 0;
};

class DA  
{ 
    class D : A
    {
    private:
        virtual void f(int) override {}
    } d;
};

class DB : public DA
{ 
    class D : B
    {
    private:
        virtual void f(char*) override {}
    } d;
};

我对此并不是100%满意,因为d成员会导致额外的语法开销,但至少它可以在不更改公共接口的情况下工作。

答案 2 :(得分:0)

修复警告的一种可能方法是在DA::f内复制DB的代码:

class DB : public DA, B 
{
    virtual void f(int i) override
    {
         // copy implementation of DA::f(int) as you cannot do
         // return DA::f(i);
    }
private:
    virtual void f(char*) override {}
};

Demo

但是删除警告的本地 pragma 似乎更合适。