函数重载在基类和派生类之间拆分的可见性
Visibility of function overloads split between base and derved classes
我正在尝试重构一些访问者模式代码以删除一些代码重复。此任务的关键是将现有 API 中的函数重载拆分为两个:一些进入基类,而另一些进入扩展该基的派生类。
在尝试在基类和派生类之间拆分 API 时,我遇到了意外的编译错误。为了抛开与访问者相关的背景,我将我的问题解开/提炼到下面的示例 (c++11( 代码中,如下所示:
#include <iostream>
class X
{
public:
virtual const char * name() const =0;
};
class Y : public X
{
public:
virtual const char * name() const override { return "Y"; }
};
class Z : public X
{
public:
virtual const char * name() const override { return "Z"; }
};
class APIBase // The API is split between this base class...
{
public:
virtual void foo(Y & y) =0;
};
class APIDerived : public APIBase // ..and this derived class
{
public:
virtual void foo(Z & z) =0;
};
class APIImplementation : public APIDerived
{
public:
virtual void foo(Y & y) override {
std::cout << "foo(" << y.name() << ")" << std::endl;
}
virtual void foo(Z & z) override {
std::cout << "foo(" << z.name() << ")" << std::endl;
}
};
class A
{
public:
APIDerived & api() { return m_api; }
private:
APIImplementation m_api;
};
int main(int argc, char * argv[])
{
Y y;
Z z;
A a;
a.api().foo(y);
a.api().foo(z);
return 0;
}
基本思想是,类 A 通过调用 api(( 提供在 APIBase 和 APIDerived 中定义的 API 的实现,然后它可以对从类 X 派生的对象进行操作,并根据它是 Y 还是 Z 执行不同的操作。
我希望这段代码在运行时给我以下输出:
foo(Y)
foo(Z)
但是,在编译此代码时,gcc 给了我以下错误:
intf.cpp: In function ‘int main(int, char**)’:
intf.cpp:57:16: error: no matching function for call to ‘APIDerived::foo(Y&)’
a.api().foo(y);
^
intf.cpp:57:16: note: candidate is:
intf.cpp:30:16: note: virtual void APIDerived::foo(Z&)
virtual void foo(Z & z) =0;
^
intf.cpp:30:16: note: no known conversion for argument 1 from ‘Y’ to ‘Z&’
有两种方法可以使此示例代码编译并提供预期的输出,但我不确定在编译器(或C++标准(眼中它们与原始代码的区别是什么。
1. 通过将两个 foo(( 纯函数声明放入 APIBase 或 APIDerived(但不在它们之间拆分(来重新组合 API,例如:
class APIBase
{
public:
virtual void foo(Y & y) =0;
virtual void foo(Z & z) =0;
};
2. 更改类 A,使其派生自 APIImplementation 并放弃 api(( 重定向调用,例如:
class A : public APIImplementation {};
int main(int argc, char * argv[])
{
Y y;
Z z;
A a;
a.foo(y);
a.foo(z);
return 0;
}
我不想这样。我也不想放弃继承而支持模板。
我对C++很陌生:请您帮助我理解为什么此示例代码无法编译,如果可能,提供不需要我采取上述步骤 (1( 或 (2( 的解决方法?
技术细节:
Platform: Centos 7, Linux 3.10.0-123.6.3.el7.x86_64
Compiler: gcc (GCC) 4.8.2 20140120 (Red Hat 4.8.2-16)
默认情况下,基类中的f
和派生类中的f
不被视为重载,并且它们之间不会执行重载。
编译器基本上是向后遍历作用域以查找一个作用域,其中至少有一个项具有要查找的名称。然后,它会查看该范围内具有该名称的所有内容,并对其执行重载解析。如果外部作用域(例如父类(中存在同名的内容,则不会包含在该重载解析中。
但是,您可以将继承的名称纳入范围:
struct base {
void foo(int);
};
class derived : public base {
using base::foo;
void foo();
};
现在,如果在派生类中调用foo
,则派生类和基类中的foo
将被视为重载集,因此正确的调用将基于您传递的参数(或缺少参数(。
- C++中std::resize(n)和std::shrink_to_fit之间的区别
- int(c) 和 c-'0' 之间的区别。C++
- 在cuda线程之间共享大量常量数据
- 在c代码之间共享数据的最佳方式
- Mix_Init和Mix_OpenAudio SDL之间的区别是什么
- C++ 使用 assign 函数的字符串与直接使用 '=' 更改值的字符串之间的区别
- VSOMEIP-2个设备之间的通信(TCP/UDP)不工作
- std::atomic和std::condition_variable wait,notify_*方法之间的区别
- 大小相等但成员数量不同的结构之间的性能差异
- 类与私有变量的其他类之间的线程安全性
- C++将向量的向量拆分为向量的N个子向量
- 在线程之间拆分任务总是值得的吗?
- C++声明和定义之间拆分默认参数值
- 如何将字符串拆分为一组 3 个字符,它们之间有空格
- 如何在标题和CPP之间拆分静态/模板类
- 在空格之间拆分字符数组
- 如何在单独的 Boost.Python 模块之间拆分继承关系
- 在不同的机器之间拆分编译
- 函数重载在基类和派生类之间拆分的可见性
- 在几个函数之间拆分任务