【问题标题】:Problems with setting up Function Pointers in Templated Class在模板类中设置函数指针的问题
【发布时间】:2010-10-26 15:04:17
【问题描述】:

我正在尝试创建一个以类为模板的通用菜单按钮类,因此我可以在任何类中制作此按钮。我想在该类中创建一个指向不同函数的 void 函数指针,因此当您单击 New Game 按钮时,它将调用 NewGame() 函数等。

我对创建函数指针的想法还有些陌生,希望得到一些建议。

我现在每次尝试使用此菜单按钮编译我的代码时都会遇到一个疯狂的链接错误。

这是错误:

错误 1 ​​错误 LNK2019:未解决 外部符号“公共:无效 __thiscall MENUBUTTON::Draw(void)" (?Draw@?$MENUBUTTON@VTitleScreen@@@@QAEXXZ) 在函数“公共: 虚空__thiscall TitleScreen::Draw(void)" (?Draw@TitleScreen@@UAEXXZ) TitleScreen.obj

菜单按钮.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();
};

菜单按钮.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();
}

如果有人对我如何以不同的方式使按钮在任何情况下动态化有任何建议,或者知道这个问题是什么,请帮助! :)

【问题讨论】:

    标签: c++ function pointers


    【解决方案1】:

    要消除链接错误,请将所有以template 开头的方法定义从.cpp 文件移动到.h 文件。在您的代码中,移动这些:

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

    它不能与.cpp 文件一起工作的原因是编译器将MENUBUTTON&lt;Foo&gt;MENUBUTTON&lt;Bar&gt; 等视为不同的类,并在使用时生成并编译这样的类。所以如果你在编译titlescreen.cpp的时候使用MENUBUTTON&lt;TitleScreen&gt;,那么MENUBUTTON&lt;TitleScreen&gt;的代码就会被编译到目标文件titlescreen.o中。但是SetButtonDraw 方法将在链接时丢失,因为它们没有在titlescreen.cpp 或它包含的任何.h 文件中定义。 MenuButton.o 也不会包含它,因为MenuButton.cpp 不需要MENUBUTTON&lt;TitleScreen&gt;

    【讨论】:

    • 谢谢,我想我现在也更好地理解了 C++ 中的模板类。
    【解决方案2】:

    只是为了澄清第一个答案,您不能拥有在标头中声明然后在单独的编译翻译单元(即 .cpp 文件)中实现的模板类。您必须将所有代码放在标题中。您可以将它们全部放在初始类声明中,也可以使用“内联”先用函数声明类,然后在标题中进一步实现特定函数。

    【讨论】:

      【解决方案3】:

      说到更好的方法......为什么你需要一个模板? 普通的旧虚函数或指向成员的指针就可以了。 这将是Command Design Pattern 的完美应用。 模板为您提供编译时多态性,而您可能正在这里寻找运行时多态性

      【讨论】:

      • 在我实施任何东西之前,我肯定会在下周研究一下。
      猜你喜欢
      • 2019-03-23
      • 1970-01-01
      • 2014-09-04
      • 1970-01-01
      • 1970-01-01
      • 2012-07-05
      • 2010-09-13
      • 1970-01-01
      • 2018-03-24
      相关资源
      最近更新 更多