在泛型和子类代码中需要相互引用的c++类

C++ classes that need to refer to each other both in generic and subclass code

本文关键字:引用 c++ 泛型 子类 代码      更新时间:2023-10-16

我有三个类,config, circuitconn,它们相互保存指针,如下所示:

struct config { /* ... */ };
struct circuit {
    config *cfg;
    /* ... */
};
struct conn {
    config *cfg;
    circuit *ckt;
    /* ... */
}

(没有访问控制和指针智能,因为这个程序已经完成了从C到c++的转换。那现在不重要

当这些类被子类化时,它们三个总是在一个组中被子类化:

struct foo_config  : config  { /* ... */ };
struct foo_circuit : circuit { /* ... */ };
struct foo_conn    : conn    { /* ... */ };

此外,foo_circuitfoo_conn中的cfg指针将始终指向foo_config的实例,foo_conn中的ckt指针将始终指向foo_circuit的实例,这是一个运行时不变量。这是目前dynamic_cast和断言强制执行的。目前有两个不同的foo s,但将来可能会有更多。

是否有可能安排事项,使cfgckt指针仍然可以访问泛型circuitconn类的方法,并具有泛型类型,但在子类的方法中,这些指针具有适当的子类类型,并且上述不变式成为编译时强制执行?如果有,怎么做?如果没有,你建议我做什么呢?

我更喜欢那些我必须为每组子类编写的样板文件数量最少的答案。如果子类定义在匿名命名空间中并且在任何头文件中不可见,我也更喜欢仍然有效的答案。

如果你用getter和setter替换所有对数据成员的直接访问,那么你就可以为每个子类定义特定类型的getter和setter,并且编译器可以使用这些来强制类型。下面是一个例子,注意我已经定义了一个模板类来简化子类的创建。

struct config { /* ... */ };
struct circuit {
private: 
    config *cfg;
protected:
    void set_cfg(config* _cfg) { cfg = _cfg; }
    config* get_cfg() { return cfg; }
};
template <typename CFG>
struct my_circuit : circuit {
public:
    // type specific setters/getters
    void set_cfg(CFG* _cfg) { circuit::set_cfg(_cfg); }
    CFG* get_cfg() { return dynamic_cast<CFG*>(circuit::get_cfg()); }
};
// below is how you define two different sets of subclasses:
struct foo_config  : config  { /* ... */ };
typedef my_circuit<foo_config> foo_circuit;
struct bar_config  : config  { /* ... */ };
typedef my_circuit<bar_config> bar_circuit;
// example usage
foo_config foo_cfg;
foo_circuit foo_ckt;
bar_config bar_cfg;
foo_ckt.set_cfg(&foo_cfg); // okay
foo_ckt.set_cfg(&bar_cfg); // not okay, compiler error!

在基类内部你不需要改变任何东西。在子类内部,您必须用相应的getter替换对这些成员变量的直接访问,以便获得适当的类型转换。注意,我将基类中的数据成员转换为private,以便编译器帮助检测子类中对这些数据成员的所有直接引用。