0

I am doing computer assignment with OpenGL

But I am new of c++. It is very different with Java.

here's I tried.

class Map {
private :
public :
    short mapkind;
    float a = 5;
    Map() 
    {}

};

class Road : public Map {
private :
public :    
    Road()
    {
        mapkind = 0;
    }
};

class Glass : public Map {
private:
public:
    float color[3] = { 0.0, 1.0, 0.0};

    Glass()
    {
        mapkind = 1;
    }
};

And then I made array.

Map* maps[10] = { new Road(),
   new Glass(), 
   new Road(), 
   new Glass(), 
   new Glass(), 
   new Road(), 
   new Road(), 
   new Glass(), 
   new Road(), 
   new Glass() };

And this is in my main loop.

for (int i = 0; i < 10; i++) {
if ((*maps)[i].mapkind == 0) {
    //draw road
    Road* temp;
    temp = (Road*)maps[i];
}
else if ((*maps)[i].mapkind == 1) {
    //draw glass
    Glass* temp;
    temp = (Glass*)maps[i];
}
else {
    //exit(4);
    printf("error %hd %d \n", (*maps)[i].mapkind);
}
}

I learned C and pointer But It's too old. I guess that In Array, putting 'new Class()' as one element would be wrong, But I don't know how to fix it.

first number is short type %hd and second one is int type %d for printing short type variable 'mapkind'

first number is short type %hd and second one is int type %d for printing short type variable 'mapkind'

ssh
  • 49
  • 6
  • 2
    Don't use a member variable to say what kind of object it is, instead learn about *virtual functions*. – Some programmer dude Mar 14 '16 at 07:10
  • If you make your classes polymorphic by adding a `virtual` method (or destructor), then you can simply use the `dynamic_cast` to check if the base class is pointing to a specific derived class or not. For example for checking if `maps[i]` is pointing to `Glass` or not use `Glass* temp = dynamic_cast(maps[i])`. Note that this works only if the class is polymorphic (has a virtual method). – Vishal Mar 14 '16 at 07:19

3 Answers3

3

The problem here is not the casting, it's how you dereference the array:

(*maps)[i].mapkind

This first dereferences maps (which gives you maps[0]) and then you use that pointer as an array, which it is not. This leads to undefined behavior.

Instead do maps[i]->mapkind (or if you want to use explicit dereferencing and dot-syntax (*(maps[i])).mapkind).


Also, you should "unlearn" C-style casting when programming in C++, it can lead to trouble when you least expect it. Instead use e.g. static_cast:

Glass* temp = static_cast<Glass*>(maps[i]);

Or like I mentioned in my comment, use virtual functions which will be called in the correct object using the correct class.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Thank you. I tried this, It works. But I have segmentation error, so I will solve it. – ssh Mar 14 '16 at 08:26
0

Aside from the things have been discussed, I'd argue that if you have to cast your objects from a baseclass to a derived class "as a rule", you are doing something wrong. Yes, it may be that you do that a few times in a whole program, but the rule should be that you have a method in the class that does the work for you, and don't cast it to the derived class to perform that task. So, of you want to draw your object, you have a Draw function:

class Map {
private :
public :
    short mapkind;
    float a = 5;
    Map() 
    {}
    virtual void Draw() = 0;
};

and then implement this function for Road, Glass, etc.

The reason I say that "you may sometimes cast" is that, say you have 30-40 different objects derived from Map, and you need to do something special to Aeroplane, which only happens in a few places, then using the cast it and then do stuff is reasonable. My compiler project used llvm::dyn_cast as a method of "if this object is this type, then special things need to be done".

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • Thank you. I know this is not good design. But I need arrays that can contains of two or more class object. your saying that adds Draw function would be good, I will apply this to my code. But I need to study what virtual function is. – ssh Mar 14 '16 at 08:36
  • The whole point of virtual functions is that they can be placed in the base-class, and you can have an array [or vector] of the base-class and then use that to call a function that is defined in the derived class. – Mats Petersson Mar 14 '16 at 21:59
-1

.Your base class should contain at least one virtual function, even tho, u must add virtual destructor, ie:

class Map {
    short mapkind;
    float a;
public :        
    Map() : a(5.0f)
    {}
    virtual ~Map(){}
    virtual short getMapkind() const { return mapkind; }
};

Override getMapkind function in derived classes. then you can use something like this:

vector<Map*> vec;
vec.push_back(new Road());
auto mk = vec.back()->getMapkind();
jonezq
  • 344
  • 1
  • 5
  • Doesn't really explain the underlying problem at all, does it? – Mats Petersson Mar 14 '16 at 07:40
  • Showed proper way how to get mapkind, then u can you C-style cast, static_cast, dynamic_cast(with RTTI), even reinterprent_cast - everything will work. – jonezq Mar 14 '16 at 08:13
  • Except the ORIGINAL problem is not that, it is that the indirection is in the wrong place. The original code, using a function to get mapkind would stil access out of bounds, and still be undefined. It does NOT help, even if it's a neater design. At least if you are going to suggest changes, make sure they are solving the problem that the OP is asking about - OR make perfectly clear that you are NOT answering the original question. – Mats Petersson Mar 14 '16 at 21:57