2009-05-15 12 views
0

Ich versuche, eine generische Menüschaltfläche zu erstellen, die einer Klasse zugewiesen ist, sodass ich diese Schaltfläche in jeder Klasse erstellen kann. Ich möchte einen void Funktion Zeiger auf verschiedene Funktionen in dieser Klasse erstellen, wenn Sie also auf die Schaltfläche Neues Spiel klicken, wird es die NewGame() Funktion usw. aufrufen.Probleme beim Einrichten von Funktionszeigern in der Vorlagenklasse

Ich bin noch ein wenig neu zu der Idee von Erstellen von Funktionszeigern und möchte einen Ratschlag.

Ich bekomme einen verrückten Link Fehler jedes Mal, wenn ich versuche, meinen Code jetzt mit diesem Menubutton zu kompilieren.

hier ist der Fehler:

Error 1 error LNK2019: unresolved external symbol "public: void __thiscall MENUBUTTON::Draw(void)" ([email protected][email protected]@@@@QAEXXZ) referenced in function "public: virtual void __thiscall TitleScreen::Draw(void)" ([email protected]@@UAEXXZ) TitleScreen.obj

MenuButton.h

template <class t> 
struct MENUBUTTON 
{ 
    SPRITE Normal;    // Sprite to display when not hovered over or pressed down 
    SPRITE Hover;    // Sprite to display when hovered over 
    RECTANGLE HoverBounds;  // The Rectangle that activates the hover flag 

    t* pClass;     // Pointer to the templated class 
    void (t::*ClickFunction)(); // Pointer to void function 

    void SetButton(int xPos, int yPos, int width, int height, int hPadLeft, int hPadTop, int hWidth, int hHeight, LPCTSTR normalFilePath, LPCTSTR hoverFilePath, t* objectClass, void (t::*ClickFunction)()); 

    bool IsMouseHover(); 

    void CheckPressed(); 

    void Draw(); 
}; 

MenuButton.cpp

#include "Global.h" 

template <class t> 
void MENUBUTTON<t>::SetButton(int xPos, int yPos, int width, int height, int hPadLeft, int hPadTop, int hWidth, int hHeight, LPCTSTR normalFilePath, LPCTSTR hoverFilePath, t* objectClass, void (t::*ClickFunction)()) 
    { 
     // Position 
     Hover.position.x = Normal.position.x = xPos; 
     Hover.position.y = Normal.position.y = yPos; 
     Hover.position.z = Normal.position.z = 0; 

     // Width/Height 
     Hover.width = Normal.width = width; 
     Hover.height = Normal.height = height; 

     // Hover RECTANGLE 
     HoverBounds.x = xPos + hPadLeft; 
     HoverBounds.y = yPos + hPadTop; 
     HoverBounds.width = hWidth; 
     HoverBounds.height = hHeight; 

     // Load the Sprites 
     LoadSprite(&Normal, normalFilePath, width, height, 1, 1); 
     LoadSprite(&Hover, hoverFilePath, width, height, 1, 1); 

     // Set the Click function pointer 
     this->pClass = objectClass; 
     this->ClickFunction = ClickFunction; 
    } 

template <class t> 
void MENUBUTTON<t>::Draw() 
{ 
    if(IsMouseHover()) 
    { 
     DrawSprite(&Hover, 0, Hover.position.x, Hover.position.y, Hover.position.z); 
    } 
    else 
    { 
     DrawSprite(&Normal, 0, Normal.position.x, Normal.position.y, Normal.position.z); 
    } 
} 

template <class t> 
bool MENUBUTTON<t>::IsMouseHover() 
{ 
    return (((InputData.MousePosition.x >= HoverBounds.x) && (InputData.MousePosition.x <= (HoverBounds.x + HoverBounds.width))) && 
     ((InputData.MousePosition.y >= HoverBounds.y) && (InputData.MousePosition.y <= (HoverBounds.y + HoverBounds.height)))) ? true : false; 

} 

Hier ist mein Titelbildschirm, der die Menü-Taste verwendet.

TitleScreen.h

class TitleScreen : public BaseState 
{ 
    // SPRITES 
    SPRITE titleScreenBG; 

    // MENU BUTTONS 
    MENUBUTTON<TitleScreen> playButton; 
    MENUBUTTON<TitleScreen> quitButton; 

    public: 
     TitleScreen(); 

     virtual void Initialize(); 
     virtual void End(); 

     virtual void Update(float dt, INPUTDATA* input); 
     virtual void Draw(); 

     void QuitGame(); 

     void NewGame(); 
}; 

TitleScreen.cpp

#include "Global.h" 

// Constructors 
TitleScreen::TitleScreen() 
{ 

} 

// Virtual Voids 
void TitleScreen::End() 
{ 

} 

void TitleScreen::Initialize() 
{ 
    this->Enabled = true; 
    this->Visible = true; 

    // Initialize sprites 
    ZeroMemory(&titleScreenBG, sizeof(SPRITE)); 
    LoadSprite(&titleScreenBG, TEXT("../../PNG/TitleScreenBG.png"), 1440, 900, 1, 1); 
    titleScreenBG.position.x = titleScreenBG.position.y = titleScreenBG.position.z = 0; 

    // Initialize buttons 
    ZeroMemory(&playButton, sizeof(MENUBUTTON<TitleScreen>)); 
    playButton.SetButton(55, 170, // x , y 
         512, 128, // width, height 
         10, 10,  // Left, Top Padding 
         400, 70, // Hover width, Hover height 
         TEXT("../../PNG/NewGame.png"), TEXT("../../PNG/NewGameH.png"), 
         this, &TitleScreen::NewGame); 

    ZeroMemory(&quitButton, sizeof(MENUBUTTON<TitleScreen>)); 
    quitButton.SetButton(55, 240, // x , y 
         512, 128, // width, height 
         10, 10,  // Left, Top Padding 
         190, 70, // Hover width, Hover height 
         TEXT("../../PNG/QuitButton.png"), TEXT("../../PNG/QuitButtonH.png"), 
         this, &TitleScreen::QuitGame); 
} 

void TitleScreen::Update(float dt, INPUTDATA* input) 
{ 

} 

void TitleScreen::Draw() 
{ 
    StartRender(); 
    DrawSprite(&titleScreenBG, 0, titleScreenBG.position.x, titleScreenBG.position.y, titleScreenBG.position.z); 
    playButton.Draw(); 
    quitButton.Draw(); 
    EndRender(); 
} 

// Public Methods 
void TitleScreen::QuitGame() 
{ 
    CloseDirect3D(); 
} 

void TitleScreen::NewGame() 
{ 
    CloseDirect3D(); 
} 

Wenn jemand einen Rat hat, wie ich die Tasten dynamisch für jeden Fall in einer anderen Art und Weise machen, oder weiß, was dieses Problem ist, bitte helfen! :)

Antwort

1

Um die Beseitigung der Verbindungsfehler zu erhalten, alle Methodendefinitionen mit template aus der .cpp-Datei in die .h Datei starten bewegen. In Ihrem Code, bewegen diese:

template <class t> void MENUBUTTON<t>::SetButton ... { ... } 
template <class t> void MENUBUTTON<t>::Draw ... { ... } 

Der Grund, warum es nicht mit der .cpp Datei ist nicht funktioniert, dass der Compiler behandelt MENUBUTTON<Foo> und MENUBUTTON<Bar> usw. als verschiedene Klassen, und es erzeugt und kompiliert eine solche Klasse, wenn es wird eingesetzt. Wenn Sie also MENUBUTTON<TitleScreen> beim Kompilieren von titlescreen.cpp verwenden, wird der Code MENUBUTTON<TitleScreen> in die Objektdatei titlescreen.o kompiliert. Aber die Methoden SetButton und Draw fehlen zur Verbindungszeit, weil sie nicht in titlescreen.cpp oder einer der .h Dateien definiert sind, die es enthält. MenuButton.o enthält es auch nicht, weil MenuButton.cpp nicht benötigt.

+0

Danke, ich glaube, ich verstehe jetzt auch die Templates in C++ besser. –

0

Nur um die erste Antwort zu klären, können Sie keine Vorlagenklasse haben, die in einer Kopfzeile deklariert und dann in einer getrennten kompilierten Übersetzungseinheit (d. H. CPP-Datei) implementiert wird. Sie müssen den gesamten Code in die Kopfzeile setzen. Sie können entweder alles in die anfängliche Klassendeklaration einfügen oder mit "inline" die Klasse zuerst mit den Funktionen deklarieren und dann die spezifischen Funktionen weiter unten in der Kopfzeile implementieren.

0

Apropos besserer Weg ... warum brauchen Sie hier eine Vorlage? Einfache alte virtuelle Funktion oder Zeiger auf Mitglied würde tun. Dies wäre eine perfekte Anwendung der Command Design Pattern. Vorlagen geben Sie kompilieren-Zeit-Polymorphismus, während Sie wahrscheinlich nach Laufzeit-Polymorphismus hier suchen.

+0

Ich schaue mir das nächste Woche genau an, bevor ich etwas umsetze. –

Verwandte Themen