1

I've got a base class, Item, and derived class, Weapon & Shield. Both overload <<.

// item(base) operator overload
ostream& operator<<(ostream& os, const Item& a_item)
{
    os << "     Item Object - " << endl;
    os << "          Name: " << a_item.m_name << endl;
    os << "          Cost: " << a_item.m_cost << endl;
    os << "          Purpose: " << a_item.m_purpose << endl;

    return os;
}

And:

// weapon(derived) operator overload
ostream & operator<<(ostream & os, const Weapon & a_weapon)
{
    os << "Weapon - " << endl;
    os << "     Name: " << a_weapon.m_name << endl;
    os << "     Cost: " << a_weapon.m_cost << endl;
    os << "     Purpose: " << a_weapon.m_purpose << endl;

    return os;
}

// shield(derived) operator overload
ostream & operator<<(ostream & os, const Shield & a_shield)
{
    os << "Shield - " << endl;
    os << "     Name: " << a_shield.m_name << endl;
    os << "     Cost: " << a_shield.m_cost << endl;
    os << "     Purpose: " << a_shield.m_purpose << endl;

    return os;
}

Now, I have a vector<Item> inventory, to which I'm adding a Weapon and a Shield. When I loop through the inventory and cout the item, I get the Item operator rather than the one for that particular item. Here's how I'm calling the cout:

// person(derived) operator overload
ostream& operator<<(ostream& os, const Person& a_person)
{
    os << "Person Object - " << endl;
    os << "     Name: " << a_person.m_name << endl;
    os << "     Level: " << a_person.m_level << endl;
    os << "     Hit Points: " << a_person.m_hit_points << endl;
    os << "     Inventory: " << endl;

    for (auto i = 0; i < a_person.m_inventory.size(); i++)
    {
        os << "     " << a_person.m_inventory[i] << endl;
    }

    return os;
}

enter image description here

My question is why is it calling the operator overload of the base, instead of the derived? Is it possible to tell it to call the one from the derived class?

PiousVenom
  • 6,888
  • 11
  • 47
  • 86
  • 1
    When you use `vector inventory`, your code suffers from [object slicing](https://stackoverflow.com/questions/274626/what-is-object-slicing). – R Sahu Jun 20 '18 at 05:33
  • You should really aim for a [mcve] that addresses the issue you're trying to figure out and nothing else. – juanchopanza Jun 20 '18 at 05:34

2 Answers2

5

In addition to the object slicing problem, your code suffers from another conceptual problem. Your expectation that the operator<< function for the derived types will be invoked at run time when you have a reference to the base class is ill-founded. That is not going to work since the functions are not polymorphic.

You have to change the strategy a bit to make them work like polymorphic functions.

  1. Implement the operator<< function only for the base class.
  2. Have virtual member functions that do the actual work.
  3. Call the virtual member function from the operator<< function.

Demonstrative code:

struct Base
{
   virtual std::ostream& print(std::ostream& os) const
   {
      // Print base class details

      return os;
   }
};

struct Derived : Base
{
   virtual std::ostream& print(std::ostream& os) const
   {
      // Do the base class printing first
      Base::print(os);

      // Print the derived class details.

      return os;
   }
};

std::ostream& operator<<(std::ostream& os, Base const& b)
{
   // This will be a polymorphic call.
   return b.print(os);
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • So, setting it up this way will allow me to still have the `vector` and call the `Print()` of the `Weapon`? – PiousVenom Jun 20 '18 at 13:47
  • @MyCodeSucks, no that is an orthogonal problem that also has to be fixed. Use a `std::vector` of smart pointers. – R Sahu Jun 20 '18 at 14:57
2

std::vector keeps its elements in its own private array, so they are stored by value. A value of type Item has always Item as its most derived class, so when you store a Weapon there, what is kept in the vector is merely an Item (the Item-part of the Weapon), and, when printed, it can only report itself as an Item.

bipll
  • 11,747
  • 1
  • 18
  • 32