我的系统具有许多可以发布/订阅的消息类型。添加新类型时,必须更新大量文件以增加对新方法类型的支持。
是否可以将带有重载纯虚拟方法的C ++类声明为可变数据结构?
编译下面的C ++程序时,类型“ MessageB
”的第二种发布方法的声明被“ MessageA
”的声明隐藏。
main.cpp:57:41:错误:没有匹配的函数可以调用'IPublisher :: publish(MessageB)'Publisher-> publish(MessageB {“ world”});
这与GCC和Clang都一致,但是Clang确实会发出有用的警告:
警告:'IPublishOne :: publish'隐藏了重载的虚拟函数[-Woverloaded-virtual] virtual void publish(const T&message)= 0;
由于MessageA和MessageB是不同的类型,为什么会发生方法隐藏?
#include <iostream>
#include <memory>
using namespace std;
template <class...Ts>
struct IPublishOne;
template <class T>
struct IPublishOne<T>
{
virtual void publish(const T& message) = 0;
};
template <class T, class... Ts>
struct IPublishOne<T, Ts...> : IPublishOne<Ts...>
{
virtual void publish(const T& message) = 0;
};
struct MessageA
{
std::string value;
};
struct MessageB
{
std::string value;
};
struct IPublisher : public IPublishOne<MessageA, MessageB>
{
virtual ~IPublisher() = default;
};
struct Publisher : public IPublisher
{
void publish(const MessageA& message) override
{
std::cout << message.value << std::endl;
}
void publish(const MessageB& message) override
{
std::cout << message.value << std::endl;
}
};
int main()
{
const std::unique_ptr<IPublisher> publisher = std::make_unique<Publisher>();
publisher->publish(MessageA{"hello"});
// this produces compile error
publisher->publish(MessageB{"world"});
return 0;
}
答案 0 :(得分:3)
为什么由于MessageA和MessageB不同而导致方法隐藏 类型?
您没有最终替代者。
IPublishOne<T, Ts...>::publish
覆盖 IPublishOne<T>::publish
,根据class.virtual/2:
如果在
vf
和$ {1}中声明了 virtual 成员函数class Base
。class Derived
,直接或间接源自成员Base
具有相同名称的函数vf
,parameter-type-list,cv-qualification, 并声明与Base::vf
相同的ref限定符,然后Derived::vf
也是 virtual (无论是否声明),并且 它会覆盖Base::vf
。
您需要的是final overrider:
在struct IPublishOne<T, Ts...>
中指定最终替代程序:
template <class T, class... Ts>
struct IPublishOne<T, Ts...> : IPublishOne<Ts...>
{
using IPublishOne<Ts...>::publish; // final overrider for
// IPublishOne<T>::publish
virtual void publish(const T& message) = 0;
};
答案 1 :(得分:1)
问题在于,在类中定义publish()
方法会隐藏所有从基类继承的publish()
方法。
您可以解决此问题,在using
中添加IPublishOne
template <class T, class... Ts>
struct IPublishOne<T, Ts...> : IPublishOne<Ts...>
{
using IPublishOne<Ts...>::publish; // <<<-------------
virtual void publish(const T& message) = 0;
};
使可见的继承publish()
可见。