隐藏私有重载虚函数?
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 {}
};
但本地 pragma 似乎更适合删除警告。
我有一个 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 {}
};
但本地 pragma 似乎更适合删除警告。