2016-03-29 55 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); 
     } 
    } 
};