Problems with setting function pointers in Templated Class

I'm trying to create a generic menu button class that is a template for the class, so I can make this button in any class. I want to create a void function pointer for different functions in this class, so when you click the New Game button it will call the NewGame () function, etc.

I'm still a little familiar with the idea of ​​creating function pointers and would like some advice.

I get a crazy link error every time I try to compile my code with this Menubutton.

here is the error:

Error 1 error LNK2019: unresolved external symbol "public: void __thiscall MENUBUTTON :: Draw (void)" (? Draw @? $ @ VTitleScreen button MENU @@@@ QAEXXZ) function reference "public: virtual void __thiscall TitleScreen :: Draw (canceled) "(? Draw @TitleScreen @@ 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;

}

      

Here is my title screen that uses a menu button.

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

      

If anyone has any advice on how I can make buttons dynamic for any occasion differently, or know what the problem is, please help! :)

0


a source to share


3 answers


To get rid of the communication error, move all method definitions template

from file .cpp

to file .h

. In your code, move them:

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

      



The reason why it does not work with the file .cpp

, is that the compiler treats MENUBUTTON<Foo>

and MENUBUTTON<Bar>

etc. as different classes, and generates and compiles such a class whenever it is used. Therefore, if you use MENUBUTTON<TitleScreen>

when compiling titlescreen.cpp

, then the code MENUBUTTON<TitleScreen>

will be compiled into an object file titlescreen.o

. But the methods SetButton

and Draw

will be absent during the link because they are not defined in titlescreen.cpp

or in any of the files .h

that it includes. MenuButton.o

will also not contain it, because it MenuButton.cpp

does not need MENUBUTTON<TitleScreen>

.

+1


a source


To clarify the first answer, you cannot have a template class that is declared in the header and then implemented in a separate compiled translation unit (i.e. cpp file). You have to put all the code in the header. You can either put all of this in the initial class declaration, or use "inline" to first declare the class with functions and then implement specific functions later in the header.



0


a source


Speaking of the best ... why do you need a template here? Plain old virtual function or member pointer. This would be an ideal application of the command design pattern . Templates give you compile-time polymorphism , although you're probably looking for run-time polymorphism here.

0


a source







All Articles