1

Say for example you have:

class Plant {
    public:
    ...public accessors, etc ...

}

Then you have a specific plant class:

class Broccoli : public Plant
{
    public:
        Broccoli(int i);
        virtual ~Broccoli();

        inline BroccoliSprite* getPlantSprite() { return _plantSprite; };

    private:
         BroccoliSprite* _plantSprite;

};

at some point the Broccoli object is stored in a vector: std::vector<Plant> vPlants;

accessing the vector and its elements I use: inline std::vector<Plant>& getPlants() { return vPlants; };

to access:

 for (int f=0; f < _f.getPlants().size(); f++)
 {
    Plant _p1 = _f.getPlants().at(f);

    cocos2d::CCSprite* s = _p1.getPlantSprite();
    ....


 }

I want to be able to use getPlantSprite() to display it to the user but the compiler tells me: No member named 'getPlantSprite' in 'Plant'

This is true, but the object in the vector is of type Plant and contains a member variable that Is the sprite I need, the getter returns it.

What I dont understand is how get access to getPlantSprite()

I guess one thing is I could change class Plant to be class Plant : <some generic object class> and store that object in the vector instead ofPlants`

or I could cast to a Broccoli.

UPDATE: So to use shared_ptr<>

I am currently doing:

 Broccoli b(tempField->getFieldNumber()); 
 tempField->getPlants().push_back(b);

This means I would be doing something like:

std::shared_ptr<Plant> object1(new Broccoli(tempField->getFieldNumber()));
tempField->getPlants().push_back(std::move(object1));

How do I now access the Broccoli object inside the shared pointer to do things to it?

Before I used to do something like:

Broccoli b(tempField->getFieldNumber());

tempField->getFieldSprite()->addChild(b.getPlantSprite(), 2);

b.getPlantSprite()->setRotation(BROCCOLI::plantRotation);

tempField->getPlants().push_back(b);

Now:

std::shared_ptr<Plant> object1(new Broccoli(tempField->getFieldNumber()));

tempField->getPlants().push_back(std::move(object1));

b.getPlantSprite()->setRotation(BROCCOLI::plantRotation);

tempField->getPlants().push_back(b);

Compiler says b. is an undeclared identifier which obviously makes sense, but I need to do more to the object after putting it inside the shared_ptr

so this might be:

std::shared_ptr<Plant> object1(new Broccoli(tempField->getFieldNumber()));

tempField->getPlants().push_back(std::move(object1));

object1->getPlantSprite()->setRotation(BROCCOLI::plantRotation);

but the compiler still says: `No member named 'getPlantSprite' in 'Plant'

UPDATE 2: to avoid object slicing, it looks like making functions in base class pure virtual might help solve this, still using shared_ptr or unique_ptr

UPDATE 3:

for (int f=0; f < _f.getPlants().size(); f++)
{
    std::shared_ptr<Plant> sbas = _f.getPlants().at(f);

    std::shared_ptr<Broccoli> sder2 = std::static_pointer_cast<Broccoli>(sbas);

    .. do stuff with `sder2`
}

in this vector there will be things like Broccoli, Asparagus, etc. I will have to use dynamic_pointer_cast, but what does this line look like:

std::shared_ptr<Plant> sbas = _f.getPlants().at(f);

std::shared_ptr<Plant?????> sder2 = std::dynamic_pointer_cast<Broccoli>(sbas);

I do store an internal ID as part of Plant that I could do a switch on to decide what type to statically cast to.....though.

Jasmine
  • 15,375
  • 10
  • 30
  • 48
  • You should probably use [`std::make_shared`](http://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared) instead of `new`: `auto b = std::make_shared(tempField->getFieldNumber());` – dyp Sep 03 '13 at 01:26
  • Polymorphism with `shared_ptr`s is analogous to polymorphism with raw pointers, you just have to use [`std::X_pointer_cast`](http://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast) instead of `X_cast`, like `std::static_pointer_cast` instead of `static_cast`. [Live example](http://coliru.stacked-crooked.com/a/c4187903a19b8aa8) (Note: you'll probably want to use a `dynamic_pointer_cast`) – dyp Sep 03 '13 at 01:36
  • are you saying: `std::shared_ptr object1(std::make_shared(tempField->getFieldNumber()));` instead of `std::shared_ptr object1(new Broccoli(tempField->getFieldNumber()));`? – Jasmine Sep 03 '13 at 01:36
  • Nope, just `auto object1 = std::make_shared( tempField->getFieldNumber() );`, see the example above. – dyp Sep 03 '13 at 01:37
  • Seems like `unique_ptr`s are more complicated if you want to cast and avoid raw pointers (see [this question](http://stackoverflow.com/questions/11002641/dynamic-casting-for-unique-ptr)). You could use a `vector>` and non-owning raw pointers for the casts, if it is otherwise clear in your project that the resulting raw pointers are non-owning. – dyp Sep 03 '13 at 01:41
  • Your last example, just above "UPDATE 2", probably invokes Undefined Behaviour (if you made it compile). Moving an object leaves that object in a pretty much undefined state. For `shared_ptr`s, it leaves the moved `shared_ptr` empty (and `shared_ptr::operator->` is `noexcept` but requires the `shared_ptr` to be non-empty). If you need to later access the element which is to be inserted in the vector, either get it anew from the vector (e.g. via `vector::back()`) or store a copy of the `shared_ptr` in the vector (i.e. leave out the `move`). – dyp Sep 03 '13 at 01:52
  • I think I am clearer. can you look at Update3? – Jasmine Sep 03 '13 at 02:27
  • so doing what I mentioned in Update3 works. – Jasmine Sep 03 '13 at 03:13
  • "I do store an internal ID as part of Plant that I could do a switch on to decide what type to statically cast to.....though." Yes, you can use a `static_pointer_cast` in this case, it'll also probably be a bit faster than a `dynamic_pointer_cast`. If you wanted to use a `dynamic_pointer_cast`, just replace the `static_pointer_cast` in your example, then check if the resulting `shared_ptr` is empty (or use or ID before the cast). Btw: don't use my naming conventions from the live example, they're just silly ;) – dyp Sep 03 '13 at 13:05
  • Thanks for all the advice. I better understand `shared_ptr` and the related. Now practice makes perfect. – Jasmine Sep 03 '13 at 14:56

1 Answers1

5

You should be storing shared_ptr<Plant> in your vector, not just Plant. With what you're currently doing, you're getting slicing, which means that you're not actually storing Broccolis, only the Plant portions thereof (and a cast to Broccoli, as you suggested at the end of your post, will not work).

Community
  • 1
  • 1
C. K. Young
  • 219,335
  • 46
  • 382
  • 435
  • Do I then need to do anything different to add to the vector or access elements from it like above? – Jasmine Sep 02 '13 at 23:30