我正在使用C ++制作游戏,并且我的派生类出现问题。我有一个名为GameScreen的基类,它有一个没有语句的vitrual void draw()函数。我还有一个名为MenuScreen的派生类,它还有一个虚拟的void draw()函数和一个名为TestMenu的MenuScreen派生类,它也有一个void draw()函数。在我的程序中,我有一个GameScreens列表,我有一个GameScreen迭代器通过调用每个GameScreens draw()函数。
问题是我在GameScreen列表中放置了一个TestMenu对象。而不是迭代器调用TestMenu的draw()函数,而是调用GameScreen类的draw()函数。有谁知道如何调用TestMenu的draw()函数而不是GameScreen中的函数。
这是功能:
// Tell each screen to draw itself.
//gsElement is a GameScreen iterator
//gsScreens is a list of type GameScreen
void Draw()
{
for (gsElement = gsScreens.begin(); gsElement != gsScreens.end(); gsElement++)
{
/*if (gsElement->ssState == Hidden)
continue;*/
gsElement->Draw();
}
}
以下是我的课程副本:
class GameScreen {
public:
string strName;
bool bIsPopup;
bool bOtherScreenHasFocus;
ScreenState ssState;
//ScreenManager smScreenManager;
GameScreen(string strName){
this->strName = strName;
}
//Determine if the screen should be drawn or not
bool IsActive(){
return !bOtherScreenHasFocus &&
(ssState == Active);
}
//------------------------------------
//Load graphics content for the screen
//------------------------------------
virtual void LoadContent(){
}
//------------------------------------
//Unload content for the screen
//------------------------------------
virtual void UnloadContent(){
}
//-------------------------------------------------------------------------
//Update changes whether the screen should be updated or not and sets
//whether the screen should be drawn or not.
//
//Input:
// bOtherScreenHasFocus - is used set whether the screen should update
// bCoveredByOtherScreen - is used to set whether the screen is drawn or not
//-------------------------------------------------------------------------
virtual void Update(bool bOtherScreenHasFocus, bool bCoveredByOtherScreen){
this->bOtherScreenHasFocus = bOtherScreenHasFocus;
//if the screen is covered by another than change the screen state to hidden
//else set the screen state to active
if(bCoveredByOtherScreen){
ssState = Hidden;
}
else{
ssState = Active;
}
}
//-----------------------------------------------------------
//Takes input from the mouse and calls appropriate actions
//-----------------------------------------------------------
virtual void HandleInput(){
}
//----------------------
//Draw content on screen
//----------------------
virtual void Draw(){
}
//--------------------------------------
//Deletes screen from the screen manager
//--------------------------------------
void ExitScreen(){
//smScreenManager.RemoveScreen(*this);
}
};
class MenuScreen: public GameScreen{
public:
vector <BUTTON> vbtnMenuEntries;
MenuScreen(string strName):GameScreen(strName){
}
virtual void Update(bool bOtherScreenHasFocus, bool bCoveredByOtherScreen){
GameScreen::Update(bOtherScreenHasFocus, bCoveredByOtherScreen);
for(unsigned int i = 0; i < vbtnMenuEntries.size(); i++){
vbtnMenuEntries[i].IsPressed();
}
}
virtual void Draw(){
GameScreen::Draw();
for(unsigned int i = 0; i < vbtnMenuEntries.size(); i++)
vbtnMenuEntries[i].Draw();
}
};
class testMenu : public MenuScreen{
public:
vector<OBJECT> test;
//OBJECT background3();
// OBJECT testPic(512, 384, buttonHover.png, 100, 40, 100, 40);
// BUTTON x(256, 384, buttonNormal.png, buttonHover.png, buttonPressed.png, 100, 40, test());
bool draw;
testMenu():MenuScreen("testMenu"){
OBJECT background3(1, 1, 0, TEXT("background.png"), 1, 1, 1024, 768);
OBJECT testPic(512, 384,0, TEXT("buttonHover.png"), 1, 1, 100, 40);
test.push_back(background3);
test.push_back(testPic);
//background3.Init(int xLoc, int yLoc, int zLoc, LPCTSTR filePath, int Rows, int Cols, int Width, int Height)
//test.push_back(background3);
// vbtnMenuEntries.push_back(x);
draw = false;
}
void Update(bool bOtherScreenHasFocus, bool bCoveredByOtherScreen){
MenuScreen::Update(bOtherScreenHasFocus, bCoveredByOtherScreen);
//cout << "X" << endl;
/*if(MouseLButton == true){
testMenu2 t;
smManager.AddScreen(t);
}*/
}
void Draw(){
//background3.Draw();
test[0].Draw();
test[1].Draw();
MenuScreen::Draw();
///*if(draw){*/
// testPic.Draw();
//}
}
/*void test(){
draw = true;
}*/
};
答案 0 :(得分:9)
如果gsScreens是一个对象列表而不是一个指针列表(如代码所示),那么你就不会存储你认为存储在其中的内容。
发生的事情是 - 您不是将TestMenu放入列表中,而是使用编译器生成的复制构造函数构建一个新的MenuScreen,并将此MenuScreen放入列表中。
C ++通过指针是多态的,所以如果你没有指针就不会有多态行为。
答案 1 :(得分:1)
要获得您所追求的多态行为并同时使用std::vector<>
,您必须将指针存储到向量中的基类类型,而不是存储值。此外,你必须记住在向量超出范围之前释放他们的记忆。
例如:
#include <vector>
#include <algorithm>
struct Base
{
virtual void Foo() = 0;
virtual ~Base() { }
};
struct Derived1 : public Base
{
void Foo() { }
};
struct Derived2 : public Base
{
void Foo() { }
};
struct delete_ptr
{
template <typename T>
void operator()(T& p)
{
delete p;
p = 0;
}
};
int wmain(int, wchar_t*[])
{
std::vector<Base*> items;
items.push_back(new Derived1);
items.push_back(new Derived2);
Base& first = items.front();
first.Foo(); // Will boil down to Derived1::Foo().
Base& last = items.back();
last.Foo(); // Will boil down to Derived2::Foo().
std::for_each(items.begin(), items.end(), delete_ptr())
};
答案 2 :(得分:0)
Curt绝对是正确的,但我只是想向它提供更多信息。
这个问题(存储基类对象而不是指针)有时被称为“切片”。
另外,我倾向于使用以下宏:
#define DISALLOW_COPYING(X) \
private: \
X(const X &); \
const X& operator= (const X& x)
然后你把它放在你的班级定义中的某个地方:
class Foo {
// ...
DISALLOW_COPYING(Foo);
};
如果另一个类试图复制该对象,则会出现编译器错误(因为这些方法被声明为私有)。如果类本身试图复制该对象,则会出现链接器错误(因为这些方法没有实现)。
答案 3 :(得分:0)
Boost(www.boost.org,我建议任何编写C ++的人使用的库)提供了一个不可复制的基类,就是这样做的。你不需要那种丑陋的宏。