2017-10-16 133 views
-2

我有以下聲明一個類A(阿文件):與模板函數循環依賴

#ifndef __A_DEFINED__ 
#define __A_DEFINED__ 

class A 
{ 
public: 
    template<typename T> inline void doThat() const; 
}; 

#endif 

和B類從該類(BH文件)推導出:

#ifndef __B_DEFINED__ 
#define __B_DEFINED__ 

#include <iostream> 
#include "A.h" 

class B : public A 
{ 
public: 
    void doThis() const { std::cout << "do this!" << std::endl; } 
}; 

#endif 

所以遠,那麼好。我的問題是,函數A ::找時間做()使用B :: doThis():在

template<typename T> inline void A::doThat() const { B b; b.doThis(); } 

一般情況下,循環依賴不會是一個問題,因爲我也只是定義了A ::找時間做() .cpp文件。但在我的情況下,doThat是一個模板函數,所以我不能這樣做。

這裏是我到目前爲止所設想的解決方案:

  1. 定義模板功能A::doThat()在.cpp文件。與此相關的問題是,我需要顯式實例化具有各種模板參數的所有調用(實際情況中可能有很多)。

  2. 在A.h中聲明A類後,添加#include "B.h",然後定義A::doThat()函數。這在Visual Studio中運行良好,但是g ++不喜歡它。

有沒有一種簡潔的方法來解決這個問題?在真實情況下,不僅有一個孩子類B,而且有幾個(B,C,D等)。函數A :: doThat()取決於它們中的所有孩子。函數B :: doThis()也是模板化的。

+2

無關:任何在一行中有兩個下劃線的標識符都被保留供實現使用。使用它們需要您自擔風險。更多信息在這裏:[有關在C++標識符中使用下劃線的規則是什麼?](https://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in- ac-identifier) – user4581301

回答

1

B類的缺省模板參數可以工作:

#include <iostream> 

// include A.h 
class B; 

class A 
{ 
public: 
    template<typename T, typename U = B> inline void doThat() const 
    { 
     U b; b.doThis(); 
    } 
}; 

// include B.h 
class B : public A 
{ 
public: 
    void doThis() const { std::cout << "do this!" << std::endl; } 
}; 

// main 
int main() 
{ 
    A a; 
    a.doThat<int>(); 
} 
+0

這隻適用於默認的模板參數,或者即使在此定義函數?我是這樣說的,因爲在真實情況下,doThat()取決於B,但也取決於孩子C,D和E. – Touloudou

+0

@Touloudou這聽起來像是一個相關的,但不同的問題與不同的答案。 – wally

1

通常是最好的方式,讓家長調用子函數聲明函數作爲家長和覆蓋純虛函數它在孩子們。

#include <iostream> 

class A 
{ 
public: 
    virtual ~A() = default; 
    template<typename T> inline void doThat() const 
    { 
     // do some other stuff 
     doThis(); 
    } 
    virtual void doThis() const = 0; // pure virtual function 
}; 

class B: public A 
{ 
public: 
    void doThis() const override 
    { 
     std::cout << "do this!" << std::endl; 
    } 
}; 

int main() 
{ 
    B b; 
    A* ap = &b; 
    ap->doThat<int>(); 
} 
+0

這裏的問題是doThis()函數也應該在實際情況下進行模板化。這意味着這將是一個虛擬模板函數,在當前C++中是不行的。 – Touloudou

+0

@Touloudou這是真正重要的信息在問題中。您應該編輯問題並添加它。如果模板沒有(或簡單)參數,則可以將模板化函數抽象爲常規模板。 – user4581301

0

下確實與g++工作:

文件A.h

#ifndef __A_DEFINED__ 
#define __A_DEFINED__ 

class A 
{ 
public: 
    template<typename T> inline void doThat() const; 
}; 

#include "B.h" 

template<typename T> inline void A::doThat() const { B b; b.doThis(); } 

#endif 

文件B.h

#include <iostream> 

#include "A.h" 

// We check for the include guard and set it AFTER the inclusion of A.h 
// to make sure that B.h is completely included from A.h again. 
// Otherwise the definition of A::doThat() would cause a compiler error 
// when a program includes B.h without having included A.h before. 
#ifndef __B_DEFINED__ 
#define __B_DEFINED__ 

class B : public A 
{ 
public: 
    void doThis() const { std::cout << "do this!" << std::endl; } 
}; 

#endif 

文件test_A.cpp

// In this test case we directly include and use only A. 
#include "A.h" 
#include "A.h" // We test whether multiple inclusion causes trouble. 

int main() { 
    A a; 
    a.doThat<int>(); 
} 

文件test_B.cpp

// In this test case we directly include and use only B. 
#include "B.h" 
#include "B.h" // We test whether multiple inclusion causes trouble. 

int main() { 
    B b; 
    b.doThat<int>(); 
    b.doThis(); 
} 

另外一個設想:

我不知道你(或某些編碼約定)是否堅持爲每個類單獨的頭文件,但如果沒有以下應工作:

你可以把class Aclass B的定義和成員函數模板的(以此順序)在一個頭文件AandB.h(或任何你喜歡的名字)中。

+0

@Touloudou根據你的想法,我得到了你用'g ++'工作的問題2.我不得不移動包含守衛(參見B.h中的評論)。 – Fabian