C ++中模板类型中的类层次结构
Posted
技术标签:
【中文标题】C ++中模板类型中的类层次结构【英文标题】:Class hierarchy in templated types in C++ 【发布时间】:2020-02-09 15:05:40 【问题描述】:我正在做一个简单的项目,其中有发布者从一个数据源中读取数据并构建事件供订阅者处理。
一个事件将拥有一个唯一指向数据的 ptr,而订阅者将拥有一个指向该事件的共享 ptr。
我想要一个事件的通用接口,以便订阅者可以订阅任意数据发布者。 但是发布者只能发布一种类型的数据。
#include <memory>
#include <iostream>
class Data
;
class ChildData : public Data
;
template<typename T>
class Event
std::unique_ptr<T> _data;
;
void someFunc(Event<Data> event)
std::cout << "hello Word" << std::endl;
int main()
Event<ChildData> event();
someFunc(event);
return 0;
但出现以下编译器错误
/home/rory/dev/cpp_sandbox/main.cpp: In function ‘int main()’:
/home/rory/dev/cpp_sandbox/main.cpp:27:19: error: could not convert ‘event’ from ‘Event<ChildData> (*)()’ to ‘Event<Data>’
someFunc(event);
^
CMakeFiles/example.dir/build.make:62: recipe for target 'CMakeFiles/example.dir/main.cpp.o' failed
make[2]: *** [CMakeFiles/example.dir/main.cpp.o] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/example.dir/all' failed
make[1]: *** [CMakeFiles/example.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
这种事情在 C++ 中可能吗?
【问题讨论】:
首先Event<ChildData> event();
声明了一个不带参数并返回Event<ChildData>
的函数。它没有声明Event<ChildData>
类型的变量。这被称为“最令人头疼的解析”。我不认为这是故意的。如果要声明默认构造的变量,请删除 ()
。
这种方法行不通。 Event<Data>
和 Event<ChildData>
是两个不同的、不相关的类,尽管 ChildData
派生自 Data
。 Event<Data>
不是您正在寻找的“通用接口”。如果您想要一个通用接口,请定义一个(作为非模板类)并让 Event<T>
从它派生并实现其方法。
【参考方案1】:
有问题的行是这样的:
Event<ChildData> event();
根据most vexing parse 规则,这被解释为函数声明。如果您的 Event
类具有初始化所有成员的默认构造函数,则可以省略括号。否则使用统一初始化语法:
Event<ChildData> event;
此外,您可能必须使用std::move
将event
传递给someFunc
,因为Event
是不可复制的,因为std::unique_ptr
数据成员。此外,您必须实现从Event<ChildData>
到Event<Data>
的转换,这是someFunc
所必需的。
我想要一个事件的通用接口,以便订阅者可以订阅任意数据发布者。但是发布者只能发布一种类型的数据。
从这个描述来看,Event
模板似乎是多余的。 Data
后代的公共接口可以在 Data
类本身中描述,因此除非需要将事件与数据分开,否则仅处理数据会更容易。
为了区分不同的事件类型,可以使用枚举。
enum class EventType
A,
B,
C
;
class Data
private:
const EventType m_type;
protected:
explicit Data(EventType type) : m_type(type)
public:
virtual ~Data() = default;
// Prohibit copying to avoid accidental slicing
Data(Data const&) = delete;
Data& opreator= (Data const&) = delete;
EventType get_type() const return m_type;
;
class ChildData :
public Data
public:
ChildData() : Data(EventType::A)
;
void receive(std::unique_ptr< Data > event)
switch (event->get_type())
case EventType::A:
std::unique_ptr< ChildData > child_event static_cast< ChildData* >(event.release()) ;
// Process ChildData
break;
case EventType::B:
// ...
case EventType::C:
// ...
void publish(std::unique_ptr< Data > event);
int main()
std::unique_ptr< ChildData > event new ChildData() ;
// Fill ChildData event
publish(std::move(event));
【讨论】:
那还是不行。Event<ChildData>
无法转换为 Event<Data>
。
我认为 OP 的问题是他们如何才能使这样的传递工作。 (我也认为他们希望函数参数实际上是一个引用,而不是按值。)
感谢您的意见。我很感激你的努力。它帮助我意识到我将要承担的概念和设计错误!实际上,我还有很多思考和阅读要做。以上是关于C ++中模板类型中的类层次结构的主要内容,如果未能解决你的问题,请参考以下文章