隐藏私有重载虚函数?

Hiding a private overloaded virtual function?

我有一个 class 层次结构,其工作方式大致如下:

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甚至不知道,当然不应该公开它。

有没有办法在不取消警告的情况下解决这个问题,即告诉编译器一切都按预期设计?

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

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 成员会导致额外的语法开销,但至少它可以在不更改 public 接口的情况下工作。

After all, DB cannot even see the hidden function (which might even be named the same by coincidence).

可访问性和可见性在 C++ 中是不同的概念。 DA::f()DB中默认[=​​25=]可见(然后被DB::f()隐藏),但不可访问,因为它在[=]中是私有的13=],并且 DB 不是 DA 的朋友。有人可能会争辩说,隐藏一个不可访问的函数是无害的,因为无论如何都无法调用它。然而,隐藏函数和不可访问函数之间的区别可能很重要,因为可见函数和不可访问函数确实参与了重载决策。如果 db 是类型 DB 的对象,那么 db.f(0) 做什么?如果 DA::f() 可见但不可访问,它将被 select 编辑为最佳匹配并且编译器将发出诊断,因为它不可访问,因此无法调用。但是,如果 DA::f() 被隐藏,编译器将 select 接受指针的重载,并将文字 0 视为空指针。

修复警告的一种可能方法是在 DB:

中复制 DA::f 的代码
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 似乎更适合删除警告。