Classes & More Classes

Pages: 12
I have will four classes:

Object
Tile
Mob
Player

Object is my base class.
Tile needs to extend Object.
Mob needs to extend Object.
Player needs to extend Mod.

I set up my Object class and then started on my Tile class. Soon I realized I didn't know how to inherit my Object class the way I wanted to, or if that is even what I should be doing.

Here is my Object class.

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
#ifndef _OBJECT_H_
#define _OBJECT_H_

class Object
{
    private:

        int id;
        int type;
        int x;
        int y;

    public:

        Object(int objID);

        void SetType(int objType);
        void SetX(int posX);
        void SetY(int posY);

        int GetID();
        int GetType();
        int GetX();
        int GetY();
}

#endif 


I believe I am lost. What should I be doing?
Last edited on
way I wanted to
What way exactly is that?
Anything wrong with class Tile : public Object {};?
I am thinking that I still want to be able to access type, x, & y directly, but not id. I also don't know how I would use Object's constructor after that to set id. id is not to be changed after being set.
Might want to look up the difference between "private" and "protected" members. I'm guessing that's what you want for type/x/y vs id.

Your Tile constructor can call the Object constructor in its initializer list:
Tile(int objID) : Object(objID) { /* BODY */ }
Last edited on
@Gaminic

Yes I think that will work. Thank you!

However in the case of the Player class, would I have Player's constructor call Mob's constructor, then have Mob's constructor call Object's constructor?
Yep!
I highly recommend that at this point you start making all your functions (including the destructor) virtual.
@L B

I just did some reading on virtual functions, and I see some benefit to it. However, I don't see the need to do that just yet. The project I am working on is a very small one, and I think it would just over complicate it for me at this point.

The game simply allows the player to click on the screen and go to that location, avoiding objects along the way. The Mobs just walk around the screen randomly.
If you ever going to use polymorphism, use virtual on all your methods (especially the destructors!) It doesn't over complicate anything... In fact, all you have to do is add the keyword virtual before all your methods... That's it! So the above Object class would be:
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
#ifndef _OBJECT_H_
#define _OBJECT_H_

class Object
{
    private:

        int id;

    protected:

        int type;
        int x;
        int y;

    public:

        Object(int objID);

        //The destructor:
        virtual ~Object();

        //I don't know if you still want these public mutator methods:
        virtual void SetType(int objType);
        virtual void SetX(int posX);
        virtual void SetY(int posY);

        virtual int GetID();

        //I assume you want these public accessor methods still:
        virtual int GetType();
        virtual int GetX();
        virtual int GetY();
}

#endif  
You put virtual in the methods that you want polymorfic behaviour. It is not necessary for all of them.
However if you have at least one virtual method, then you should make the destructor virtual too.

Those accessor are already bad, ¿but why make them virtual? They refer to variables of the parent class ¿when will you override the behaviour?
ne555 wrote:
They refer to variables of the parent class
You don't know that, there is no body to these methods.

ne555 wrote:
why make them virtual... when will you override the behaviour
I don't know, but it dosen't hurt performance to do so. You might decide to run some debugging later in a derived class so that getType() always returns 0, (or something like that.)

ne555 wrote:
Those accessor are already bad
Why are the accessors bad?
Last edited on
ne555 wrote:
why make them virtual... when will you override the behaviour
Mathhead200 wrote:
I don't know, but it dosen't hurt performance to do so.

It can hurt performance. Virtual functions are often impossible for the compiler to inline and the virtual lookup has some overhead.
But I do know what they do, based on meaningful name
Actually getType could be virtual as an implementation of RTTI. However it's got the type variable, so if you want to return 0; then simply assign it that value.
Accessors break encapsulation and put the responsibillity in the wrong class.

By the way, please don't misquote. It seems that I'm saying exactly the opposite that I meant.
ne555 is right, you should only virtualize the destructor and any member functions that should be run based on the true type of an instance rather than the type it looks like. Getters and setters should NEVER be virtual.
Well it appears we have different approaches. I don't see how declaring a getter/setter as virtual could be bad, and the whole point of getter and setter methods is abstraction. The other programmer(s) need not know that there is a variable somewhere with the return value.

What I meant about performance was: I was under the impression that once one method is declared virtual, it makes no difference if the rest are virtual in performance time (although I didn't think about inline functions.)

Also, it was not my intention to mis-quote.
Im confused as to why those setters/getters are bad. Is it just the virtual part of it? Or are getters/setters bad? :O
If a function is virtual then it may be redefined by an inheriting class. Why in the world would an inheriting class need to change a getter or setter? It sure can't change the base class' private variables, why should it be able to change the behavior of the functions that deal with them?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//Interfaces!

template <typename T> struct Matrix {
    virtual ~Matrix() {};
    
    virtual int getWidth() = 0;
    virtual int getHeight() = 0;
    virtual T get(int row, int col) = 0;
    virtual void set(int row, int col, T value) = 0;
};


class TwoByTwo : public Matrix<double> {
 private:
    double values[4];

 public:
    TwoByTwo() { values[0] = values[1] = values[2] = values[3] = 0; }

    virtual int getWidth() { return 2; }
    virtual int getHeight() { return 2; }
    virtual double get(int row, int col) { return values[2*row + col]; }
    virtual void set(int row, int col, double value) { values[2*row + col] = value; }
};


Also, does it really matter if there is a (good) reason? What is your reasoning as to not make them virtual? Can you explain when that would be a good idea?
Last edited on
Did I not just explain myself?
Also:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//Interfaces!

template <typename T> struct Matrix {
    virtual ~Matrix() {};
    
    int getWidth(){ return(width); }
    int getHeight(){ return(height); }
    virtual T get(int row, int col) = 0;
    virtual void set(int row, int col, T value) = 0;
protected:
    int width, height; //you can do this in pure virtual classes :p that's why their constructors get called
};


class TwoByTwo : public Matrix<double> {
 private:
    double values[4];

 public:
    TwoByTwo() { values[0] = values[1] = values[2] = values[3] = 0; width = height = 2; }

    virtual double get(int row, int col) { return values[2*row + col]; }
    virtual void set(int row, int col, double value) { values[2*row + col] = value; }
};
Last edited on
No you didn't. You just asked "why" someone would want to do it, implying there is no good reason. However, you never explained why it could be bad...

And you should look up interfaces, as they are not a (real) thing in C++, but more in OOP design. (A way to avoid some multiple inheritance issues.) Note that the class Matrix dosen't have any implemented methods (minus the default destructor) and has no variables. Also notice that, there is no need to store the width and height as properties like that in the derived class.

This matrix interface supplied all the stuff you need to be able to do with a matrix without giving any restriction to the derived class on how to do it. Also the matrix interface does not add to the size in memory of the derived class.
Last edited on
Pages: 12