【问题标题】:Circular dependency in templated inheritance hierarchy模板化继承层次结构中的循环依赖
【发布时间】:2016-07-17 12:05:12
【问题描述】:

我有一个模板化的基类,它有多个子类并提供一个抽象的执行方法。孩子以不同的方式实现此方法,并且可以将执行调用委托给基类的尾向量中的对象。 为了将对象链接到尾部,Base 类提供了一些方法(createChild1、createChild2)。代码如下:

base.h

#pragma once

#include <memory>
#include <vector>

template<typename T>
class Child1;

template<typename T>
class Child2;

template<typename T>
class Base {
public:
    std::vector<std::unique_ptr<Base<T>>> tail;

    virtual void execute(const T &t) = 0;

    Base<T> &createChild1() {
        auto child = std::make_unique<Child1<T>>();
        tail.push_back(std::move(child));
        return *tail.back().get();
    }

    Base<T> &createChild2() {
        auto child = std::make_unique<Child2<T>>();
        tail.push_back(std::move(child));
        return *tail.back().get();
    }
};

child1.h

#pragma once

#include "base.h"

template<typename T>
class Child1 : public Base<T> {
public:
    virtual void execute(const T &t) {
        // do something with t
    }
};

child2.h

#pragma once

#include "base.h"

template<typename T>
class Child2 : public Base<T> {
public:
    virtual void execute(const T &t) {
        // do something with t
        // then delegate to t
        for (auto &next : tail) {
            next->execute(t);
        }
    }
};

main.cpp

#include <iostream>

#include "child1.h"

using namespace std;

int main(int argc, char **argv) {
    Child1<int> c;
    c.createChild2().createChild1();
    c.execute(10);
    return 0;
}

如果我尝试编译,我会得到“未定义模板 'Child2' 的隐式实例化”,因为在 Base 中,模板类 Child2 只是前向声明的,此时它的主体是未知的。在 Child1 和 Child2 前面前向声明 Base 并在 Base 中包含 Child1 和 Child2 的定义并不能解决问题,因为这样 Child2 无法访问 tail。 如何解决这种循环依赖? Child1、Child2 和 Base 中的代码可以更改,但我想保留在 main 中链接 create 调用的可能性(因此必须在 Base 类中声明 create 方法)。

【问题讨论】:

  • 您应该能够将Base&lt;T&gt; &amp;createChild1() 和Base&lt;T&gt; &amp;createChild2() 的定义移动到一个名为base.tpp 的文件中,然后将它作为您包含在main 中的最后一个文件。这有点 hacky,所以我只是建议它作为评论。
  • 实际上用 this->tail 替换 tail 就可以了。还是谢谢你:)

标签: c++ templates c++11 c++14 circular-dependency


【解决方案1】:

解决方案是使用 this-> 作为对 tail 的访问的前缀。因此只需更改 child2.h:

#pragma once

#include "base.h"

template<typename T>
class Child2 : public Base<T> {
public:
    virtual void execute(const T &t) {
        // do something with t
        // then delegate to t
        for (auto &next : this->tail) {
            next->execute(t);
        }
    }
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-16
    • 1970-01-01
    • 2016-08-01
    • 1970-01-01
    • 2014-12-22
    • 1970-01-01
    • 2014-08-28
    相关资源
    最近更新 更多