Проблемы с настройкой указателей функций в шаблонном классе - PullRequest
0 голосов
/ 16 мая 2009

Я пытаюсь создать общий класс кнопок меню, который настроен на класс, поэтому я могу создать эту кнопку в любом классе. Я хочу создать указатель на пустую функцию для различных функций в этом классе, поэтому при нажатии на кнопку «Новая игра» она вызовет функцию NewGame () и т. Д.

Я все еще немного новичок в идее создания указателей на функции и хотел бы получить совет.

Я получаю сумасшедшую ошибку ссылки каждый раз, когда пытаюсь скомпилировать свой код с помощью этого меню.

вот ошибка:

Ошибка 1, ошибка LNK2019: не устранена внешний символ "public: void __thiscall MENUBUTTON :: Draw (void) " (? Draw @? $ @ VTitleScreen кнопку MENU @@@@ QAEXXZ) упоминается в функции "public: виртуальная пустота __thiscall TitleScreen :: Draw (аннулируются)» (? 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;

}

Вот мой титульный экран, использующий кнопку меню.

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

Если у кого-нибудь есть советы о том, как я могу сделать кнопки динамическими для любого случая по-другому, или знаете, в чем проблема, пожалуйста, помогите! :)

Ответы [ 3 ]

1 голос
/ 16 мая 2009

Чтобы избавиться от ошибки связи, переместите все определения методов, начиная с template, из файла .cpp в файл .h. В вашем коде переместите эти:

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

Причина, по которой он не работает с файлом .cpp, заключается в том, что компилятор обрабатывает MENUBUTTON<Foo> и MENUBUTTON<Bar> и т. Д. Как разные классы и генерирует и компилирует такой класс при каждом его использовании. Так что если вы используете MENUBUTTON<TitleScreen> при компиляции titlescreen.cpp, то код MENUBUTTON<TitleScreen> будет скомпилирован в объектный файл titlescreen.o. Но методы SetButton и Draw будут отсутствовать во время соединения, потому что они не определены в titlescreen.cpp или в любом из .h файлов, которые он включает. MenuButton.o тоже не будет содержать его, потому что MenuButton.cpp не нужно MENUBUTTON<TitleScreen>.

0 голосов
/ 16 мая 2009

Говоря о лучшем способе ... зачем вам здесь шаблон? Обычная старая виртуальная функция или указатель на член будет делать. Это было бы идеальным применением шаблона проектирования команд . Шаблоны дают вам полиморфизм времени компиляции , в то время как вы, вероятно, ищете полиморфизм времени исполнения здесь.

0 голосов
/ 16 мая 2009

Просто чтобы уточнить первый ответ, вы не можете иметь класс шаблона, который объявлен в заголовке, а затем реализован в отдельном скомпилированном модуле перевода (то есть в файле .cpp). Вы должны поместить весь код в заголовок. Вы можете либо поместить все это в первоначальное объявление класса, либо с помощью «inline» сначала объявить класс с функциями, а затем реализовать специальные функции в заголовке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...