关于继承:C ++派生类问题

关于继承:C ++派生类问题

C++ Derived Class problems

我正在用C ++进行游戏,派生类遇到了问题。 我有一个称为GameScreen的基类,该基类具有无声明的虚空draw()函数。 我也有一个名为MenuScreen的派生类,它也有一个虚拟的void draw()函数,还有一个从MenuScreen的名为TestMenu的派生类,它也有一个虚空的draw()函数。 在我的程序中,我有一个GameScreens列表,我有一个GameScreen迭代器通过调用每个GameScreens draw()函数来传递。

问题是我已经在GameScreen列表上放置了一个TestMenu对象。 代替迭代器调用TestMenu的draw()函数,而是调用GameScreen类的draw()函数。 有谁知道我怎么能调用TestMenu的draw()函数而不是GameScreen中的那个。

这是函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 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();
    }
}

这是我的课程的副本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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.webp, 100, 40, 100, 40);
//  BUTTON x(256, 384, buttonNormal.webp, buttonHover.webp, buttonPressed.webp, 100, 40, test());
    bool draw;

    testMenu():MenuScreen("testMenu"){
        OBJECT background3(1, 1, 0, TEXT("background.webp"), 1, 1, 1024, 768);
        OBJECT testPic(512, 384,0, TEXT("buttonHover.webp"), 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;
}*/


};

如果gsScreens是对象列表而不是指针列表(如代码所示),那么您将不会存储您认为存储在其中的内容。

发生的事情是-您实际上是在使用编译器生成的复制构造函数构造一个新的MenuScreen并将此MenuScreen放入列表中,而不是将TestMenu放入列表中。

C ++通过指针是多态的,因此,如果没有指针,您将不会得到多态的行为。


为了获得您要遵循的多态行为,同时使用std::vector<>,必须在向量中存储指向基类类型的指针,而不是存储值。同样,您必须记住在向量超出范围之前释放它们的内存。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <vector>
#include

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


Boost(www.boost.org,我建议使用C ++进行编码的任何人都建议使用的库)提供了一个不可复制的基类,可以做到这一点。您不需要那种丑陋的宏。


Curt是绝对正确的,但是我想向它提供更多信息。

这个问题(存储基类对象,而不是指针)有时被称为"切片"。

另外,我倾向于使用以下宏:

1
2
3
4
#define DISALLOW_COPYING(X) \
    private: \
        X(const X &); \
        const X& operator= (const X& x)

然后将其放在类定义中的某个位置:

1
2
3
4
class Foo {
    // ...
    DISALLOW_COPYING(Foo);
};

如果另一个类尝试复制该对象,则会出现编译器错误(因为方法被声明为私有)。如果类本身尝试复制对象,则会收到链接器错误(因为这些方法没有实现)。


推荐阅读

    excel怎么用乘法函数

    excel怎么用乘法函数,乘法,函数,哪个,excel乘法函数怎么用?1、首先用鼠标选中要计算的单元格。2、然后选中单元格后点击左上方工具栏的fx公

    excel中乘法函数是什么?

    excel中乘法函数是什么?,乘法,函数,什么,打开表格,在C1单元格中输入“=A1*B1”乘法公式。以此类推到多个单元。1、A1*B1=C1的Excel乘法公式

    标准差excel用什么函数?

    标准差excel用什么函数?,函数,标准,什么,在数据单元格的下方输入l标准差公式函数公式“=STDEVPA(C2:C6)”。按下回车,求出标准公差值。详细

    excel常用函数都有哪些?

    excel常用函数都有哪些?,函数,哪些,常用,1、SUM函数:SUM函数的作用是求和。函数公式为=sum()例如:统计一个单元格区域:=sum(A1:A10)  统计多个

    EXCEL最常用的函数有哪些?

    EXCEL最常用的函数有哪些?,函数,哪些,常用,一、IF函数作用:条件判断,根据判断结果返回值。用法:IF(条件,条件符合时返回的值,条件不符合时返回