C++ 使用特定重载函数的声明
此代码C++ 使用特定重载函数的声明,c++,c++14,C++,C++14,此代码 struct Foo{ void f(){ f(0); } private: void f(int){} }; struct Bar : private Foo{ using Foo::f; }; int main() { Bar b; b.f(); } 因为Foo::f(int)是private。我对Foo::f(int)不感兴趣,我只想要Foo::f(),它是public,所以我觉得应该有办法做到这一点 我可以想出
struct Foo{
void f(){
f(0);
}
private:
void f(int){}
};
struct Bar : private Foo{
using Foo::f;
};
int main() {
Bar b;
b.f();
}
因为Foo::f(int)
是private
。我对Foo::f(int)
不感兴趣,我只想要Foo::f()
,它是public
,所以我觉得应该有办法做到这一点
我可以想出一些变通办法:
Foo::f(int)
重命名为Foo::p_f(int)
,但这是多余的,不允许f
Bar::foo()
Foo
继承public
ly,因为~Foo()
不是virtual
(也不应该是)f
s公开
会很容易意外地破坏Foo
和Bar
代码>?或者使用一种没有相关缺点的变通方法?如果您的f(int)
应该是private
,并且永远不会是公共API的一部分,那么您不应该关心将其重命名为fimpl
:
struct Foo{
void f(){
fimpl(0);
}
private:
void fimpl(int){}
};
另一方面,如果f(int)
是公共API的通用版本,并且您还需要一个带有特定值的方便包装器,那么您可以使用提供默认参数并使f(int)
apublic
成员
struct Foo{
void f(int = 0){}
};
最后,如果您需要几个提供特定整数值的命名函数,那么我建议重命名这些包装器
struct Foo{
void f(int) {} // general interface
void sensible_name1() { f(0); }
void sensible_name2() { f(1); } // etc.
}
您的代码当前从Foo
派生为private
。因此,Foo::f()
是Bar
中的私有方法。您可以通过将类声明更改为structbar:publicfoo
来改变这一点
有关一些背景信息,请参阅下的“私有继承”一节。具体而言,本节解释如下:
[w] 当类使用私有成员访问说明符从基类派生时,基类的所有公共成员和受保护成员都可以作为派生类的私有成员访问(基类的私有成员除非是友好成员,否则永远无法访问)
基类中没有虚拟析构函数不是自动的。只有当您有一个指向基类的指针(或引用),而该基类实际上指向(或引用)一个子类实例,并且您销毁了该实例时,才会使用UB。在你展示的代码中(无可否认很简单),没有公共继承的UB。让它们具有相同的名称实际上是一个坏主意,它坏的原因包括使用声明混乱。我建议阅读“非虚拟接口”,它也有助于减少这种混乱。为什么不将Foo::f(int)
作为受保护的方法呢?任何使用Bar
或Foo
的代码仍然只能访问Foo::f(void)
,因此接口是一致的。另一种解决方案是从另一个类派生Foo
,比如说FooInterface
。然后在栏中
可以使用FooInterface::f
@Archimaredes说。如果我将Foo::f(int)
设置为受保护,那么Bar::f(int)
将成为公共的
。这是错误的@有趣的是,这个措辞有点含糊不清。考虑< <代码> bar >代码>的情况:<代码>空隙f(int)=删除;<代码>。然后因为会有冲突,规范说没有引入与Foo::f(int)
重载对应的名称。第一条规则说,没有给出此名称的访问冲突。但是重载函数的最后一句话说,必须为所有名称指定一个潜在的访问冲突。我不认为这是故意的:如果Foo中的void f(int)
是名称f
的唯一组成部分,那么规范要求不提供访问冲突。f(int=0)
本质上使f(int)
公开,这不是一个好的选择。我想我必须手动标记private
函数。