好奇的循环继承与C++中的混合

Curious circular inheritance with mix-ins in C++

本文关键字:混合 C++ 继承 循环 好奇      更新时间:2023-10-16

在这里解开循环继承的好方法是什么?

class Node {
   // ...
public:
   list<Node*> neighbors() { /* ... */ }
   void update() { }
}
template<class NodeType>
class HasImportance : public virtual NodeType {
   double m_importance = 0.0;
public:
   void receive_importance(double imp) { /* ... */ }
   void give_importance() {
      for (auto neighbor : this->neighbors())
         neighbor->receive_importance(m_importance /* ... */);
   }
};
class TrafficLight : public HasImportance<TrafficLight>, virtual Node {
public:
   list<TrafficLight*> neighbors() { ... }
   void update() { give_importance(); /* ... */ }
};

它失败(gcc 4.7.0),因为TrafficLight是一个不完整的类型当HasImportance尝试从它继承时。

真正的问题是 HasImportance 需要知道返回的类型 neighbors() .如果HasImportance继承自 Node,则认为neighbors()返回一个列表 Node*,而不是TrafficLight*,因此不会知道它可以调用项目receive_importance()。类似如果HasImportance根本没有继承,则出现问题。

顺便说一句,我想做的是做一些混合来帮助定义各种轻松使用不同类型的图表,并分别对每个混入进行单元测试。为例如,我应该能够通过编写来定义交通信号灯图的节点类像class TrafficLight : public HasImportance, HasState<3>, virtual Node { }.

我想出了三种方法来解决这个问题,但看起来都很丑陋。(1) static_cast<NodeType*> .(2)TrafficLight通过其 this在其构造函数中HasImportance。这边 HasImportance根本不需要继承;它只是存储一个指向 (ahem) 本身的指针,模板参数提供指针。(3) 将Node作为类模板,如下所示:

template<class NodeType>
class Node {
public:
   list<NodeType*> neighbors() { /* ... */ }
}
class TrafficLight : public HasImportance<Node<TrafficLight>> { /* ... */ }

编译并且不会引入this的免费副本,但似乎...有点太好奇了。

这里有代码气味吗?我应该完全接近这些图表吗不同的方式?

(3) 但有点不同。

template <class NodeType>
class Node { ... };
template<class NodeType>
class HasImportance : public virtual Node<NodeType> { ... };
class TrafficLight : public HasImportance<TrafficLight> { ... };

对我来说看起来完全直截了当,并不比 CRTP 本身更好奇。