2016-03-29 49 views
1

我有一个模板化的基类,它具有多个子类并提供抽象执行方法。孩子们以不同的方式实现这个方法,并且可以将执行的调用委托给Base类的尾部向量中的对象。 为了将对象链接到尾部,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并将Child1和Child2的定义包含在Base中并不能解决问题,因为Child2不能访问尾部。 我该如何解决这个循环依赖问题? Child1,Child2和Base中的代码可以更改,但我想保留将main调用链接的可能性(因此,必须在Base类中声明create方法)。

+0

你应该能够基本&createChild1()'和'基地&createChild2()''的定义移动到一个文件名为base.tpp然后做出主要包含的最后一个文件。这是有点hacky,所以我只是建议它作为一个评论。 – NathanOliver

+0

实际上用this-> tail来替换尾部可以完成这项工作。不管怎样,谢谢你 :) – freakout

回答

0

该解决方案以this->作为前缀访问尾部。因此只是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); 
     } 
    } 
};