我有一个类似于以下的类层次结构:
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
甚至不知道它,当然也不应该暴露它。
有没有办法在不停用该警告的情况下修复此问题,即告诉编译器所有内容都按预期设计?
答案 0 :(得分:3)
毕竟,DB甚至看不到隐藏的功能(甚至可能巧合地命名相同)。
可访问性和可见性是C ++中的不同概念。默认情况下,DA::f()
在DB
内可见(然后由DB::f()
隐藏),但它无法访问,因为它在DA
内是私有的,DB
不是DA
的朋友。有人可能会争辩说隐藏一个无法访问的功能是无害的,因为无论如何都无法调用它。但是,隐藏和不可访问之间的区别可能很大,因为可见和不可访问的功能确实参与了重载决策。如果db
是DB
类型的对象,那么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 {}
};
但是删除警告的本地 pragma 似乎更合适。