0

I'm having problems getting a vector of objects to print the name of the derived class rather then the base class.

These are my classes

#include <vector>
#include <iostream>

using namespace std;

class Object
{
    string name;
public:
    string getName()
    {
        return name;
    }
};

class Flashlight : public Object
{
    string name = "Flashlight";
public:
    string getName();
};

This is my main, it has a vector of the objects and at this point just needs to print out their names.

int main()
{
    vector<Object> items;
    items.push_back(*new Flashlight);

    for(int i = 0; i < items.size(); i++)
    {
        cout << i+1 << " " << items.at(i).getName();
    }
}

Right now if I assign something to the name in Object it will print that but its not using the derived classes values, I just want it to inherit the function then use its own values with it. I've tried implementing the function in the base classes(but seeing as I could have a lot of those in future it would lead to lots of redundant code) but that doesn't work either.

PaperBirdMaster
  • 12,806
  • 9
  • 48
  • 94
breezy
  • 3
  • 3
  • You need to have vector of pointers – ST3 Oct 09 '13 at 06:49
  • 1
    Your code suffers from object slicing. Because you have a `vector`, any `Flashlight` is *sliced* to an Object when you add it to your vector. You need a `vector`. There are other issues with your code but I guess they're just attempts to correct what is the fundmental error of object slicing. – john Oct 09 '13 at 06:53
  • @john: The attempt at overriding member variable is just as serious problem. Both have to be addressed. – Jan Hudec Oct 09 '13 at 06:55

3 Answers3

3

Instead of declaring variable 'name' in derived classes, initialize the variables value as custom value for that derived class. Also I would suggest you to make getName method as virtual. You also do not need to override getName method in derived classes if you just want to output name.

Adarsh Kumar
  • 1,134
  • 7
  • 21
1

Try this way:

int main()
{
    vector<Object *> items;
    items.push_back(new Flashlight);

    for(int i = 0; i < items.size(); i++)
    {
        cout << i+1 << " " << items.at(i)->getName();
    }
}

Also as mentioned in another answer it would be good to use virtual methods read about it here.

What is more you need to use constructor to set value for variable name. You can read about them here

You should try this way:

class Object
{
private:
    string name;
public:
    Object() : name("Object")
    {}
    Object(string str) : name(str)
    {}

    string getName()
    {
        return name;
    }
};

class Flashlight : public Object
{
public:
    Flashlight() : Object("Flashlight")
    {}

    string getName();
};
Community
  • 1
  • 1
ST3
  • 8,826
  • 3
  • 68
  • 92
  • This is only part of the problem. The variable is still not initialized properly. – Jan Hudec Oct 09 '13 at 06:53
  • Yeah this worked, I tried using pointers earlier but was using them wrong, thanks for your help! – breezy Oct 09 '13 at 07:07
  • @user2861504 If it was really helpful you should accept an answer. That is how SO system works –  Oct 09 '13 at 07:13
1

Your code has two problems:

  1. getName() is not virtual. This means that the actual function called is decided at compile time, based on the variable static type. So, if your variable is of type Object, Object& or Object* (or any const variation on those), function Object::getName() will be called, regardless of the actual type of the object referred to or pointed to by your variable (the dynamic type).
  2. You have a vector<Object>, which means that all objects stored in it are of type Object. You can try to put a Flashlight object in it, but only the Object part will be copied into the vector. If you need polymorphism in a vector<>, you need a vector of pointers (or even better, smart pointers).

So you have to do two things to get the desired behaviour:

  1. Declare function getName() as virtual string getName() (even better, virtual const string& getName() const)
  2. Declare items as vector<Object*> items (even better, use an appropriate smart pointer such as unique_ptr<> instead of a raw pointer)
Gorpik
  • 10,940
  • 4
  • 36
  • 56