隐藏一个私有的重载虚函数?

9

我有一个类层次结构,大致如下:

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甚至不知道它的存在,而且肯定不应该暴露出来。

有没有一种方法可以在不停用警告的情况下解决这个问题,即告诉编译器一切都是按照预期设计的?


请查看此链接:https://dev59.com/UnRC5IYBdhLWcg3wROtQ - Mquinteiro
@jodag:我无法将f设置为非虚函数,因为它会覆盖A中的一个函数。而且由于A是私有继承的,所以它也是私有的。 - Sacchan
4
可以覆盖一个私有虚函数,因此警告可能是合理的。 - user2672107
@manni66 很有趣,谢谢。我同意在这种情况下警告是合理的,但我仍然希望有一种方法告诉编译器这是有意的。 - Sacchan
1
你的问题最后以这样的话结束:“即告诉编译器所有东西都是按照意图设计的?”我相信这个问题在我给出的链接中已经得到了回答。Clang用户手册基本上也陈述了同样的内容。你只需要在单行代码中禁用即可,这也是你向“编译器说”某些事情的唯一实际方式......相关指令在用户手册中可以找到...... - Dr t
显示剩余5条评论
3个回答

3
毕竟,DB甚至不能看到隐藏的函数(甚至可能是同名的巧合)。
在C++中,可访问性和可见性是不同的概念。DA::f() 默认情况下在DB内部是可见的(然后被DB::f()隐藏),但它不可访问,因为它在DA内部是私有的,而且DB不是DA的友元。有人可能会认为隐藏一个不可访问的函数是无害的,因为它无论如何都无法被调用。然而,隐藏和不可访问之间的区别可能是重要的,因为可见但不可访问的函数确实参与重载解析。如果db是类型为DB的对象,则db.f(0)会发生什么?如果DA::f()是可见但不可访问的,则它将被选为最佳匹配项,并且编译器将发出诊断,因为它不可访问,因此无法调用。然而,如果DA::f()被隐藏,编译器将选择接受指针的重载,并将字面值0视为null指针。

足够正确。在我的真实示例中(它要复杂得多),两个签名中的对象实际上不能被解释为彼此,因此它并不是那么有害。 - Sacchan

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;
};

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


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 {}
};

演示

但是使用本地的pragma来消除警告似乎更为合适。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接