0

I have some Object structs that look like this:

struct Object {
   string type;
   Color c;
   float ambient, diffuse;
};

struct Sphere: Object {
   Point center;
   float radius;
};

struct Square: Object {
   Point loc;
   float len;
};

And I have a vector that is filled with Sphere and Square structs:

vector<Object> objs;
Sphere sp = //sphere stuff
Square sq = //square stuff
objs.push_back(sp);
objs.push_back(sq);

I can access the values in the parent struct just fine, but I am having trouble figuring out how to access the values in the Sphere and Square structs. This is what I am doing right now:

cout << objs.at(i).type << endl; //This works
cout << objs.at(i).center.x << endl; //Not working

Does anyone know how to do this?

Arnold Hotz
  • 179
  • 1
  • 3
  • 8
  • 1
    First [read about object slicing](http://stackoverflow.com/questions/274626/what-is-object-slicing). Then learn more about *pointers*. And finally about [upcasting and (more specifically) ***downcasting***](https://www.tutorialcup.com/cplusplus/upcasting-downcasting.htm) and how to use [`dynamic_cast`](http://en.cppreference.com/w/cpp/language/dynamic_cast). Then you should know how to fix your problem. – Some programmer dude Apr 07 '17 at 06:48

1 Answers1

1

You can't, they don't exist any more. You are not storing Squares or Spheres in the vector, you are just storing Objects. You should read What is object slicing?.

That said, if you were instead to store pointers to Objects, std::vector<Object*> you could pass pointers to the objects of the derived types. But then how would you know which element in the vector was a Square and which was a Sphere. The whole purpose of having a base class would be to provide an interface to the functionality you want, through a virtual function, which the derived classes implement in different ways:

struct Base {
    virtual void foo() { std::cout << "foo in base\n"; }
};
struct Derived1 : Base {
    void foo() override { std::cout << "foo in Derived1\n"; }
};
struct Derived2 : Base {
    void foo() override { std::cout << "foo in Derived2\n"; }
};

Derived2 d;
Base* b = &d;
b->foo(); // prints "foo in Derived2\n"

That said, to get a Square* from an Object*, use static_cast<Square*>(objP) if you know for sure it is a Square, and dynamic_cast<Square*>(objP) if you are not certain (it will return a null pointer if you are wrong). Having to do this probably indicates a bad design though!


Also, please reconsider your use of what are often considered bad practices: using namespace std; and endl (those are links to explanations).

Community
  • 1
  • 1
BoBTFish
  • 19,167
  • 3
  • 49
  • 76
  • 1
    Good point, thanks! Clearly I avoid it so much I forgot how it works. – BoBTFish Apr 07 '17 at 06:59
  • `dynamic_cast` will throw upon error, though :) – Quentin Apr 07 '17 at 09:20
  • @Quentin My above comment was a response to (since removed) Some Programmer Guy pointing out that it returns null for pointers, throws for references. I had originally incorrectly said that it will throw. – BoBTFish Apr 07 '17 at 12:22
  • I haven't seen that comment, just wanted to complete it in case it had gone just "Nope, `dynamic_cast` returns `nullptr`" without mentioning the reference case. – Quentin Apr 07 '17 at 12:28