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&lt;ChildData&gt; event(); 声明了一个不带参数并返回Event&lt;ChildData&gt;函数。它没有声明Event&lt;ChildData&gt; 类型的变量。这被称为“最令人头疼的解析”。我不认为这是故意的。如果要声明默认构造的变量,请删除 () 这种方法行不通。 Event&lt;Data&gt;Event&lt;ChildData&gt; 是两个不同的、不相关的类,尽管 ChildData 派生自 DataEvent&lt;Data&gt; 不是您正在寻找的“通用接口”。如果您想要一个通用接口,请定义一个(作为非模板类​​)并让 Event&lt;T&gt; 从它派生并实现其方法。 【参考方案1】:

有问题的行是这样的:

Event<ChildData> event();

根据most vexing parse 规则,这被解释为函数声明。如果您的 Event 类具有初始化所有成员的默认构造函数,则可以省略括号。否则使用统一初始化语法:

Event<ChildData> event;

此外,您可能必须使用std::moveevent 传递给someFunc,因为Event 是不可复制的,因为std::unique_ptr 数据成员。此外,您必须实现从Event&lt;ChildData&gt;Event&lt;Data&gt; 的转换,这是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&lt;ChildData&gt; 无法转换为 Event&lt;Data&gt; 我认为 OP 的问题是他们如何才能使这样的传递工作。 (我也认为他们希望函数参数实际上是一个引用,而不是按值。) 感谢您的意见。我很感激你的努力。它帮助我意识到我将要承担的概念和设计错误!实际上,我还有很多思考和阅读要做。

以上是关于C ++中模板类型中的类层次结构的主要内容,如果未能解决你的问题,请参考以下文章

[C/C++]详解C++中的模板

[C/C++]详解C++中的模板

用于存储类层次结构中的任何类的 c++ 类

2022暑期复习-Day6

来自子类型的 C++ 模板特化

我可以将一个类与模板中的另一个类关联(使用 C++17 变体)吗?