2010-11-21 74 views
4

嘿傢伙。感謝點擊。我正在努力與包括。基本上,我正在嘗試創建一個模板類,其中有一個函數可以接受該模板的特定實例。我做了以下人爲的例子來說明這一點。轉發聲明/包含模板類 - 「不完整類型的無效使用」

比方說,我有一個標記有模板(通用)類型數據的個人世界。我有一個特定的個人,稱爲國王。所有的個人都應該能夠在國王面前跪下。一般來說,個人可以被標記爲任何東西。國王以數字標記(第一,第二位國王)。

的誤差

g++ -g -O2 -Wall -Wno-sign-compare -Iinclude -DHAVE_CONFIG_H -c -o Individual.o Individual.cpp 
g++ -g -O2 -Wall -Wno-sign-compare -Iinclude -DHAVE_CONFIG_H -c -o King.o King.cpp 
In file included from King.h:3, 
       from King.cpp:2: 
Individual.h: In member function ‘void Individual<Data>::KneelBeforeTheKing(King*)’: 
Individual.h:21: error: invalid use of incomplete type ‘struct King’ 
Individual.h:2: error: forward declaration of ‘struct King’ 
make: *** [King.o] Error 1 

Individual.h(Individual.cpp爲空)

//Individual.h 
#pragma once 
class King; 
#include "King.h" 
#include <cstdlib> 
#include <cstdio> 

template <typename Data> class Individual 
{ 
protected: 
    Data d; 

public: 

    void Breathe() 
    { 
     printf("Breathing...\n"); 
    }; 

    void KneelBeforeTheKing(King* king) 
    { 
     king->CommandToKneel(); 
     printf("Kneeling...\n"); 
    }; 

    Individual(Data a_d):d(a_d){}; 
}; 

King.h

//King.h 
#pragma once 
#include "Individual.h" 
#include <cstdlib> 
#include <cstdio> 

class King : public Individual<int> 
{ 
protected: 

    void CommandToKneel(); 

public: 

    King(int a_d): 
     Individual<int>(a_d) 
    { 
     printf("I am the No. %d King\n", d); 
    }; 
}; 

King.cpp

//King.cpp 
#include "King.h" 
#include <string> 

int main(int argc, char** argv) 
{ 
    Individual<std::string> person("Townsperson"); 
    King* king = new King(1); 
    king->Breathe(); 
    person.Breathe(); 
    person.KneelBeforeTheKing(king); 

} 

void King::CommandToKneel() 
{ 
    printf("Kneel before me!\n"); 
} 

的Makefile

CXX = g++ 
CXXFLAGS = -g -O2 -Wall -Wno-sign-compare -Iinclude -DHAVE_CONFIG_H 
OBJS = Individual.o King.o 

test: $(OBJS) 
    $(CXX) -o [email protected] $^ 

clean: 
    rm -rf $(OBJS) test 

all: test 

回答

3

你的兩個職業國王和個人是非常緊密耦合。

把它放在這樣的兩個頭裏是行不通的,因爲兩者都需要對方。

如果你的類必須被設計,然後這樣:

  1. 首先定義類個人,但沒有實現KneelBeforeTheKing,剛剛宣佈的功能。

  2. 然後定義特大

  3. 然後實現上述方法。

但是,您的設計可能都是錯誤的。例如,您的模板類有很多不依賴於tamplated類型的方法,包括KneelBeforeTheKing,並且應該重新模板化。

+0

我在想我的設計是不正確的,因爲我碰到的問題似乎有點人爲的問題。我需要一個模板化的課程的原因是存儲模板化的數據(一個國王被標記爲第N個國王,一個人被標記爲字符串作爲他們的名字,另一種類型的人可以被標記爲人的號碼,即人# 234" )。有沒有辦法存儲模板化的數據,而無需製作模板類? – SharkCop 2010-11-21 20:00:44

+0

@TheChariot:默認情況下(除非您在代碼中聲明)模板實例化是不相關的類。如果您有一個想要用語言表達的概念(「個人」),並且符合該概念的不同實體共享通用功能,請考慮使用繼承。基類不會有任何存儲的數據,每個派生類將添加特定的數據(一個普通人的字符串,一個未命名人員的數字......)在你的設計中,儘管他們共享一些方法,「Individual 」和'個人'不能通過相同的接口傳遞。 – 2010-11-22 09:00:33

3
error: invalid use of incomplete type ‘struct King’ 

這意味着,你只申報不King定義它。你有通告包括問題(Individual.hKing.h包括對方)。應該在這個問題上提出一些建議。

+0

只是爲了讓您知道,在gamedev.net文章的鏈接已損壞。文章似乎已被刪除。 – 2011-09-25 20:54:13

+0

@Chris:謝謝,修正 – fredoverflow 2011-09-26 05:58:36

2

嗯,這裏的問題與模板無關。

您正在調用基類中後代的特殊功能。這幾乎總是一個糟糕的設計標誌。

反轉類怎麼樣?像這樣的東西(可能有錯誤):

template < typename PersonType > 
class Person : PersonType 
{ 
    public: 
     void command_to_kneel() { PersonType::command_to_kneel(); } 
     void kneel_before_king(Person<King>* king) { king->command_to_kneel(); } 
     void breathe() { } 
}; 

int main() 
{ 
    Person<King> king; 
    Person<Knight> knight; 
    knight.kneel_before_king(&king); 
} 
+0

雖然在基類中調用後代通常是一種糟糕的設計,但錯誤並非如此。編譯器抱怨'King'在實例化'Individual'時是不完整的,並且*對於調用派生方法的基類沒有問題,但派生的方法在調用位置尚未定義。 – 2010-11-22 08:54:57

1

您可以通過添加另一個基類(例如NobleBase)對類國王打破依賴:

struct NobleBase 
{ 
    virtual void KneelBefore() = 0; 
}; 


class King : public Individual<int>, 
      public NobleBase 

,改變方法
void KneelBeforeTheKing(King* king)
這個
void KneelBeforeTheKing(NobleBase* king)

然後你需要包括頭NobleBase類。

0

不考慮語法和編譯器錯誤,我認爲最大的問題是你的個人告訴國王告訴自己跪下。

void KneelBeforeTheKing(King* king) 
{ 
    king->CommandToKneel(); 
    printf("Kneeling...\n"); 
}; 

正如Let_Me_Be指出的那樣,這是設計問題而不是語法問題。實際上,國王應該決定個人什麼時候下跪,所以任何對CommandToKneel()的調用都來自國王本人,並且以一組個人作爲論證來指定誰被指揮。

語法問題是您正在嘗試使用尚未定義的功能。 King的所有前向聲明都告訴Individual的頭文件有一個稱爲King的類型。那時編譯器對King的成員一無所知,因爲你沒有包含聲明這些成員的頭文件,也沒有在King使用它之前將它定義在任何地方。然而,正如已經指出的那樣,在其基本類型(即個體)的聲明中對派生類型(即King)的任何類型的引用都是不好的設計。基類不應該知道它的派生類型。

相關問題