3

I Have two classes:

First:

class Thing {
public:
    int code;
    string name;
    string description;
    int location;
    bool canCarry;

    Thing(int _code, string _name, string _desc, int _loc, bool _canCarry) {
        code = _code;
        name = _name;
        description = _desc;
        location = _loc;
        canCarry = _canCarry;
    }
};

Second:

class Door: public Thing {

private:
    bool open;

public:

    int targetLocation;

    Door(int _code, string _name, string _desc, int _loc, int _targetLoc) :
            Thing(_code, _name, _desc, _loc, false) {
        open = false;
        targetLocation = _targetLoc;
    }
    void Use() {
        open = true;
    }
    void Close() {
        open = false;
    }
    bool isOpen() {
        return open;
    }
};

Forget private/public atributes...

I need to store some objects of base class and some objects of derived class, something like this:

vector < Thing*> allThings;
things.push_back(new Thing(THING1, "THING1", "some thing", LOC1, true));
things.push_back(new Door(DOOR1, "DOOR1", "some door", LOC1, LOC2));

But in this case, functions Use(), Open(), and isOpen() will not be reachable because of slicing..

Do you have some suggestions, how to store these objects together without creating new structure of vector<Thing*> and vector<Door*>??

Thanks

David G
  • 94,763
  • 41
  • 167
  • 253
Majak
  • 1,543
  • 1
  • 14
  • 28
  • 1
    If you are storing `Thing*`s, there will not be slicing (You don't destroy the dervide class data, you just don't know it is there at this point). Your `Door` objects will be intact, you will just need some way of getting them back later if you want to use the derived class functions. – BoBTFish Oct 30 '13 at 14:19

2 Answers2

6

A good solution to a problem when you need a container of objects with polymorphic behavior is a vector of unique pointers:

std::vector<std::unique_ptr<Thing>>

There would be no slicing in this situation, but you would have to figure out when it's OK to call Use(), Open(), and isOpen().

If you can move the methods from the derived class into the base, go for it; if you cannot do that because it makes no sense for a Thing to have isOpen(), consider using a more advanced solution, such as the Visitor Pattern:

class Thing;
class Door;
struct Visitor {
    virtual void visitThing(Thing &t) = 0;
    virtual void visitDoor(Door &d) = 0;
};
class Thing {
    ...
    virtual void accept(Visitor &v) {
        v.visitThing(*this);
    }
};
class Door : public Thing {
    ...
    virtual void accept(Visitor &v) {
        v.visitDoor(*this);
    }
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • For the Visitor Pattern solution - Why do the member funcs have to be Pure virtual as you showed, as the classes Door or thing are not seen to be inheriting from Visitor? Also your link seems to be pointed to wikipedia article for Iterator Pattern, rather than Visitor pattern. – goldenmean Oct 31 '13 at 12:51
  • @goldenmean The functions do not need to be pure virtual, but they usually are. Neither `Door` nor `Thing` should inherit `Visitor`, because these classes are *visitable*, not *visitors*. They allow a `Visitor` to visit themselves (hence the `Accept` function). Your program would create a `std::vector>`, create a class that inherits from `Visitor`, and pass that object in turn to every element of the vector. Elements will call back the visitor, telling in what type they are. See the link in the answer for more explanation - this pattern is very well worth understanding. – Sergey Kalinichenko Oct 31 '13 at 13:21
1

Store pointers instead of instances, and declare public and protected methods as virtual in the base class(es).

erenon
  • 18,838
  • 2
  • 61
  • 93