我怎样才能从模板派生两次,并让子类交互

How can I derive from a template twice, and have the subclasses interact?

本文关键字:两次 交互 子类 派生      更新时间:2023-10-16

这是我的问题:我写了两个基类:Wire和CircuitComponent。这两者几乎相似到足以衍生出一个共同的超类,但事实并非如此。Wire只能与CircuitComponent连接,CircuitComponent只能与Wire连接。除了类型之外,实现是相同的,所以自然而然地我认为模板就是答案。

这是模板,我有一个派生自TwoTypeMesh<Wire, CircuitComponent>的 Wire 类和一个派生自 TwoTypeMesh<CircuitComponent, Wire> 的 CircuitComponent 类:

template <class thisType, class otherType>
class TwoTypeMesh {
    std::set<otherType *> neighbors;
public:
    void join(otherType * n){
        if (neighbors.find(n) != neighbors.end()) {
            return;
        } else {
            neighbors.insert(n);
            n->join(this);
        }
    }
    void disconnect(otherType * n){
        if (neighbors.find(n) == neighbors.end()) {
            return;
        } else {
            neighbors.erase(n);
            n->disconnect(this);
        }
    }
};

问题是我无法编译它,它抱怨n->join(this)原因的行thisTwoTypeMesh<Wire, CircuitComponent> 类型(Wire 的超类),但join只为wire定义。

到目前为止,我

最好的理论是我不应该进行子类化,也许是typedef,但我还没有设法让它工作。

使代码编译的微创方法确实是使用 typedef,标记类或简单的枚举:

enum MeshType { MeshTypeWire, MeshTypeCircuitComponent };
template <MeshType thisType>
class TwoTypeMesh {
    // calculate 'otherType' from 'thisType' (prevents usage mistakes):
    static const MeshType otherType =
        thisType == MeshTypeWire ? MeshTypeCircuitComponent :
        /* else */                 MeshTypeWire ;
    std::set< TypeTwoMesh<otherType> *> neighbors;
public:
    void join(TypeTwoMesh<otherType> * n){
        if (neighbors.find(n) != neighbors.end()) {
            return;
        } else {
            neighbors.insert(n);
            n->join(this);
        }
    }
    void disconnect(TypeTwoMesh<otherType> * n){
        if (neighbors.find(n) == neighbors.end()) {
            return;
        } else {
            neighbors.erase(n);
            n->disconnect(this);
        }
    }
};
typedef TwoTypeMesh<MeshTypeWire> Wire;
typedef TwoTypeMesh<CircuitComponent> CircuitComponent;

将 join() 移到类之外:

void join(Wire &w, CircuitComponent &j);
void join(CircuitComponent &j, Wire &w);

您可能需要使函数成为类的好友才能访问私有数据成员。

为了解决您的特定编译错误,您应该能够在调用n->join中static_cast this thisType*

您似乎不小心重新发明了 CRTP:一个将派生类作为模板参数的模板基类。只是永远不要从 T 以外的任何类中的 TwoTypeMesh<T,U> 继承,并使 TwoTypeMesh 的构造函数受到保护以防止直接实例化。然后,您可以确定 TwoTypeMesh<T, something> 的任何实例都是 T 实例(或 T 的派生类)的基类子对象,因此T* static_cast是有效的。