Jump to content

Operator Overloading with a class hierarchy

- - - - -

  • Please log in to reply
2 replies to this topic

#1
flodywan

flodywan

    Newbie

  • Members
  • Pip
  • 9 posts
Hi guys

I have a program that's setup with a general "item" class, and a "grocery_item" class that inherits the item class. I then have an "array" class that has an array of item pointers(so they can be dynamically bound to other items).

I first overloaded the [] operator for the array class, and it returns an item&. I'm then trying to overload the << operator (only for the grocery_item class, I'll add more later) so i can do: cout << array[i];
But, this isn't working. So my question is:

What's going on here? Is the reason it doesn't work because array[i] returns just a general item and not a grocery_item(or any other type of item as needed)? What can I do so that the right class's overloaded operator is called?

Thanks in advance!


class item

//general item. Will be used for derived items and will use

//virtual functions for the derived classes.

{

  public:

    item();

    virtual ~item();

    virtual int add() {return 0;};

    virtual int display(){return 0;};

  

  protected:

    item * next; //pointer to next item since it will be in a LLL

    char * name; //name of the item

};






class grocery_item: public item

{

  public:

    grocery_item();

    ~grocery_item();

    int add();

    int display();

    friend ostream & operator << (ostream&, const grocery_item&);

    

  protected:

    float cost;  

};






class array

{

  public:

  array();

  ~array();

  item & operator [] (int);

  

  private:

  item * list[4];

};


array::array()

{

  for (int i = 0; i < 4; ++i)

  {

    list[i] = new grocery_item;

  }

}



array::~array()

{


}




item & array::operator [] (int index) 

{

  item * temp = new item;

  temp = list[index];

  

  return *temp;

}














grocery_item::grocery_item()

{

  cost = 0;

}



grocery_item::~grocery_item()

{


}



int grocery_item::add()

{ 

  char temp[40];

  cout <<"What is the name of the item? \n";

  cin.get(temp, 40, '\n');

  cin.get();

  name = new char[strlen(temp)+1];

  strcpy(name, temp);

  

  cout <<"What is the cost of the item? \n";

  cin >> cost;

  

  return 0;

}



int grocery_item::display()

{


  return 0;

}


ostream & operator << (ostream & out, const grocery_item & obj)

{

  if (!obj.name)

  {

    out <<"NO ITEM \n";

    return out;

  }

  

  out << obj.cost << endl;


  return out;

}



item::item()

{

  name = NULL;

}



item::~item()

{

  delete [] name;

}







#2
julmuri

julmuri

    Programmer

  • Members
  • PipPipPipPip
  • 139 posts

flodywan said:

What's going on here? Is the reason it doesn't work because array[i] returns just a general item and not a grocery_item(or any other type of item as needed)? What can I do so that the right class's overloaded operator is called?

Thanks in advance!
Yes. You cant call grocery items members on item instance.
Compiler cant tell if item instance is actually grocery item instance, and so it wont let it compile.

Theres alot of ways you could work around this.
class Stringable
{
public:
    //
    // ...
    virtual ~Stringable()
    {
    }

    virtual std::string toString() const = 0;

private:
    friend std::ostream & operator<<( std::ostream&, const Stringable& );

}; // class Stringable

std::ostream & operator<<( std::ostream& stream, const Stringable& stringable )
{
    return ( stream << stringable.toString() );
}


class Item
    : public Stringable
{
public:
    Item( const std::string name = "", const std::string desc = "" )
        : name_( name )
        , desc_( desc )
    {
    }

    virtual ~Item()
    {
    }

    virtual std::string toString() const
    {
        std::ostringstream stream;

        stream << "Item name:"
               << name_
               << std::endl
               << "Item description:"
               << desc_
               << std::endl;

        return stream.str();
    }

private:
    std::string name_;
    std::string desc_;

    Item( const Item& );
    Item& operator=( const Item& );

}; // class Item

class SpecializedItem
    : public Item
{
public:
    SpecializedItem( const std::string name = "", const std::string desc = "", int price = 0 )
        : Item( name, desc )
        , price_( price )
    {
    }

    virtual ~SpecializedItem()
    {
    }

    virtual std::string toString() const
    {
        std::ostringstream stream;

        stream << Item::toString()
               << "Item price:"
               << price_
               << std::endl;

        return stream.str();
    }

private:
    int price_;

    SpecializedItem( const SpecializedItem& );
    SpecializedItem& operator=( const SpecializedItem& );

}; // class SpecializedItem


int main( int argc, char* argv[] )
{
    SpecializedItem item( "Test item", "Test description", 10 ); Item* p = &item;

    std::cout << *p;
    return 0;
}

Or maybe:
class Writable
{
public:
    //
    // ...
    virtual ~Writable()
    {
    }

    virtual void write( std::ostream& stream ) = 0;


}; // class Writable


class Item
    : public Writable
{
public:
    Item( const std::string name = "", const std::string desc = "" )
        : name_( name )
        , desc_( desc )
    {
    }

    virtual ~Item()
    {
    }

    virtual void write( std::ostream& stream )
    {
        stream << "Item name:"
               << name_
               << std::endl
               << "Item description:"
               << desc_
               << std::endl;
    }

private:
    std::string name_;
    std::string desc_;

    Item( const Item& );
    Item& operator=( const Item& );

}; // class Item

class SpecializedItem
    : public Item
{
public:
    SpecializedItem( const std::string name = "", const std::string desc = "", int price = 0 )
        : Item( name, desc )
        , price_( price )
    {
    }

    virtual ~SpecializedItem()
    {
    }

    virtual void write( std::ostream& stream )
    {
        Item::write( stream );

        stream << "Item price:"
               << price_
               << std::endl;
    }

private:
    int price_;

    SpecializedItem( const SpecializedItem& );
    SpecializedItem& operator=( const SpecializedItem& );

}; // class SpecializedItem


int main( int argc, char* argv[] )
{
    SpecializedItem item( "Test item", "Test description", 10 ); Item* p = &item;

    p->write( std::cout );
    return 0;
}

Obiviously you can leave item abstract / empty or whatever if you dont wanna write it.
Or you could some kind of upcasting in item << operator, least intrusive but can be slow.
Hope this helps. (:
std::string s("oberq zhpu?");std::for_each(s.begin(),s.end(),[&](char&c){c=~c;c=~c-0x01/(~(c|0x20)/0x0D*0x02-0x0B)*0x0D;});std::cout<<s;

#3
flodywan

flodywan

    Newbie

  • Members
  • Pip
  • 9 posts
Thanks for the response. I'm having a little trouble understanding though. First, do you need the stringable class? Or could you just have the item and specializedItem class? Also, you have:


std::ostream & operator<<( std::ostream& stream, const Stringable& stringable )

{

    return ( stream << stringable.toString() );

}

I'm confused by this return statement. I'm used to simply doing return stream; What does this do exactly?

Thanks again. I'm sure this stuff's really good I'm just trying to comprehend it all.




1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users