簡體   English   中英

在模板類中設置函數指針的問題

[英]Problems with setting up Function Pointers in Templated Class

我正在嘗試創建一個模板化到類的通用菜單按鈕類,因此可以在任何類中使用此按鈕。 我想創建一個指向該類中不同函數的void函數指針,因此當您單擊New Game按鈕時,它將調用NewGame()函數等。

我對創建函數指針的想法還有些陌生,並希望獲得一些建議。

每次我現在嘗試使用此Menubutton編譯代碼時,都會遇到瘋狂的鏈接錯誤。

這是錯誤:

錯誤1錯誤LNK2019:未解決的外部符號“公共:void __thiscall MENUBUTTON :: Draw(void)”(?Draw @?$ MENUBUTTON @ VTitleScreen @@@@@@ QAEXXZ)在函數“公共:虛擬void __thiscall TitleScreen :: Draw( void)”(?Draw @ TitleScreen @@ UAEXXZ)TitleScreen.obj

菜單按鈕

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;

}

這是我的標題屏幕,它使用菜單按鈕。

標題屏幕

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();
}

如果有人對我如何使按鈕在任何情況下都可以動態變化有任何建議,或者知道這是什么問題,請提供幫助! :)

要擺脫鏈接錯誤,請將所有以template開頭的方法定義從.cpp文件移動到.h文件。 在您的代碼中,移動這些:

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

它不能與.cpp文件一起使用的原因是,編譯器將MENUBUTTON<Foo>MENUBUTTON<Bar>等視為不同的類,並且只要使用它就生成並編譯這樣的類。 因此,如果在編譯titlescreen.cpp時使用MENUBUTTON<TitleScreen> ,則MENUBUTTON<TitleScreen>代碼將被編譯到目標文件titlescreen.o 但是, SetButtonDraw方法在鏈接時將丟失,因為它們未在titlescreen.cpp或它包含的任何.h文件中定義。 MenuButton.o也將不包含它,因為MenuButton.cpp不需要MENUBUTTON<TitleScreen>

僅為了闡明第一個答案,您不能擁有在標頭中聲明然后在單獨的編譯翻譯單元(即.cpp文件)中實現的模板類。 您必須將所有代碼放在標頭中。 您可以將其全部放入初始類聲明中,也可以使用“內聯”首先通過函數聲明該類,然后在標頭中進一步實現特定的函數。

說到更好的方法...為什么在這里需要模板? 普通的舊虛擬函數或指向成員的指針都可以。 這將是Command Design Pattern的完美應用。 模板為您提供了編譯時多態性 ,而您可能正在這里尋找運行時多態性

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM