1

Jumping off of the above question Making a vector of instances of different subclasses : when implementing a vector of (pointers to) different subclasses (initialized as vector<Base*> objects), I expect to be able to access the correct member variables based on the subclass called.

Below is sample code:

#include <iostream>
#include <vector>
#include <memory>

using namespace std;

class Entity {
public:

    int index;
    Entity() {};
    virtual ~Entity() {};
    virtual void hit() = 0;
};
class Mesh : public Entity {

public:
    int index;
    Mesh(int x) {this->index=x;};
    virtual void hit() {}
};

int main() {
    vector<unique_ptr<Entity>> objects;
    objects.push_back(unique_ptr<Entity>(new Mesh(35)));
    objects.push_back(unique_ptr<Entity>(new Mesh(10)));

    for ( int i = 0 ; i < objects.size() ; i++ )
        cout << objects[i]->index << endl;

    return 0;
}                                                                                                                                                                          

Where I expect

35
10

to be printed, meanwhile I get instead.

0
0

How can I access the correct member variable values in this scenario?

Christophe
  • 68,716
  • 7
  • 72
  • 138
Ilknur Mustafa
  • 301
  • 2
  • 11
  • 1
    You redefine `int index;`, you set 35 and 10 to `Mesh::index` but print out `Entity::index`. – 273K Mar 26 '22 at 19:33
  • @273K is there a way to access ```Mesh::index``` through ```vector``` ? – Ilknur Mustafa Mar 26 '22 at 19:37
  • There is, but presumably you want to access the base one. – Ben Mar 26 '22 at 19:41
  • @Ben I want to access the member *variables* of the subclasses, I'm looking for a way to store instances of different subclasses in a common vector – Ilknur Mustafa Mar 26 '22 at 19:53
  • Then you need a `dynamic_cast`. But having a child shadow a parents variable is asking for trouble. – Ben Mar 26 '22 at 20:29
  • 1
    @Ben The parent will never use that variable, it's supposed to be a purely abstract class, I suppose that should be fine? – Ilknur Mustafa Mar 26 '22 at 20:55
  • Why do you need `Mesh::index`? What's wrong with using `Entity::index` throughout the program? – n. m. could be an AI Mar 26 '22 at 21:13
  • @n.1.8e9-where's-my-sharem. In my usecase I specifically need a container for the various subclasses, each subclass will have its own ```index``` variable. Entity is a base class that all of these subclasses derive from. The reason I have ```index``` in Entity is that it would give me an error saying that the base class does not have this variable, therefore the code segment in my question wouldn't compile. – Ilknur Mustafa Mar 26 '22 at 21:15
  • 3
    I think you are confused about the way inheritance works. A variable declared in the base class will be inherited by any derived classes, no need to declare it again in each. And as you have seen, doing that is in fact counter-productive, so just remove those declarations and your code will start working. – Paul Sanders Mar 26 '22 at 21:28
  • *each subclass will have its own index variable* Why? This is not normal. If all subclasses have the same member variable, then it rightfully belongs to the base class. Try removing `index` from all subclasses and see what happens. Does anything get broken? Note that adding `index` to `Entity` without removing it from derived classes will not help you. Member variables in a base class are unrelated to member variables in a derived class, even when they have the same name. – n. m. could be an AI Mar 26 '22 at 21:28
  • 1
    @PaulSanders this was the correct answer, the fact that the member variable would also be inherited went over my head... thank you! – Ilknur Mustafa Mar 26 '22 at 22:46

1 Answers1

1

The problem is due to a misunderstanding on inheritance. If you redefine your Mesh as follows, it would work as expected:

class Mesh : public Entity {

public:              
    //int index;     // No don't redefine:  here you'd have two different indexes 
    Mesh(int x) {this->index=x;};
    void hit() override {}   // extraa safety: use override instead of virtual to be sure to override
}; 

Online demo

Not related to the problem, but some more thoughts:

  • You can of course only use the interface of the base class (here Entity).
  • It is not very prudent to expose the index member publicly. A safer option would be to have it private, and access it via a public getter. If the index should be set only at construction, the Entity constructor should take care of it, otherwise you could consider a public setter.
Christophe
  • 68,716
  • 7
  • 72
  • 138