首页 / 知识

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

2023-04-16 21:48:00

关于继承: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);
};

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


派生类继承函数基类

最新内容

相关内容

猜你喜欢