cody
cody

Reputation: 157

Overloading >> operator for a base class

So I have a base class Animal which has 2 classes inheriting from it, which are cat and dog. Both classes are redefining a pure virtual method speak which just couts "meow" for cat and "woof" for dog. In in my main function I want to be able to do some thing like this:

int main (void) {
  Animal a;
  dog d;

  while (cin  >> a) //is this even possible? would it be cin >> d; instead?
   cout << a << endl;



  return(0);
}

SO this should cout the animals speak function, but how can I go about doing so? Also, I'm confused, if you dont know the type of animal the user is going to cin then how can you determine which speak function to use, would you use a template class?

Upvotes: 2

Views: 3736

Answers (4)

Robᵩ
Robᵩ

Reputation: 168626

You can't do precisely what you want. That is, you can't

Animal a;
std::cin >> a;

and expect the type of 'a' to change. Fundamentally, objects are not polymorphic -- pointers and references are polymorphic.

Knowing that, you can do something almost like what you want:

Animal* pA;
std::cin >> pA;
std::cout << *pA << "\n";
delete pA;

You can accomplish this by overloading

istream& operator>>(istream&, Animal*&);

to create (via new) an object of the run-time indicated type.

Consider this program:

#include <iostream>
class Animal {
public:
  virtual void speak(std::ostream& os) const = 0;
  virtual ~Animal() {} // must be virtual
};
class Dog : public Animal {
public:
  void speak(std::ostream& os) const { os << "woof"; }
};
class Cat : public Animal {
public:
  void speak(std::ostream& os) const { os << "meow"; }
};
std::ostream& operator<<(std::ostream& os, const Animal& being) {
  being.speak(os);
  return os;
}

std::istream& operator>>(std::istream& is, Animal*& zygote) {
  std::string species;
  is >> species;

  // fetch remainder of line with std::getline()

  if(species == "cat") {
    // parse remainder of line

    // Finally, create a Cat
    zygote = new Cat;
    return is;
  }
  if(species == "dog") {
    // parse remainder of line

    // and create a Dog
    zygote = new Dog;
    return is;
  }

  // Hmm, unknown species? Probably not safe to create
  std::cerr << "Warning! Unknown species. Could be dangerous!\n";
  is.setstate(std::ios::failbit);
  zygote = 0;
  return is;
}

int main () {
  Animal *pPet;

  while(std::cin >> pPet) {
    std::cout << *pPet << "\n";
    delete pPet;
  }
}

Upvotes: 1

esskar
esskar

Reputation: 10940

for the << operator, it is kinda okay

friend ostream &operator<<(ostream &output, const Animal & animal)     //output
{
    return output << animal.speak();
} 

for the input it is more complex, and i do not know if you can do it directly with Animal but you could build an AnimalLoader

class AnimalLoader {
    Animal* _animal;

public:
    AnimalLoader() : _animal(NULL) { }

    ~AnimalLoader() { if(_animal) delete _animal; }

    Animal *GetAnimal() 
    {
        Animal *retval = _animal;
        _animal = NULL;
        return retval; 
    }

    friend istream & operator >> ( istream &input, AnimalLoader &animalLoader )
    {
        if(_animal) delete _animal;
        std::string animalStr;
        input >> animalStr;
        if(animalStr == "dog")
            _animal = new Dog();
        else if(animalStr == "cat")
           _animal = new Cat();
        else
           _animal = NULL;

        return input;
    }
};

so you can then call

int main (void) {
    AnimalLoader animalLoader;

    while (cin  >> animalLoader) {
        Animal *animal = animalLoader.GetAnimal();
        if(animal != NULL) {
             cout << *animal << endl;
             delete animal;
        }
        else {
             cout << "ERROR: Could not read Animal." << endl;   
        }
    }
    return(0);
}

EDIT 1 forgot to call speak()

EDIT 2 applied it to OP example

Upvotes: 0

AusCBloke
AusCBloke

Reputation: 18492

Here's an example of overriding operator<<, which calls a public member function speak(). If you need access to private members in the overloaded operator<<, make it a friend.

#include <iostream>

class Animal {
   public:
      virtual std::string speak(void) = 0;
};

class Dog : public Animal {
   std::string speak() { return "woof"; }
};

class Cat : public Animal {
   std::string speak() { return "meow"; }
};

std::ostream& operator<<(std::ostream& out, Animal& a) {
    out << a.speak();
    return out;
}

int main (void) {
   Dog d;
   Cat c;

   Animal &a = d;
   std::cout << a << std::endl;

   Animal &a2 = c;
   std::cout << a2 << std::endl;

   return 0;
}

You should be able to work out how to do similar for operator>>.

Also, I'm confused, if you dont know the type of animal the user is going to cin then how can you determine which speak function to use, would you use a template class?

That's the idea behind dynamic binding/polymorphism. a and a2 are references to derived types of Animal and, since speak() is virtual, the v-table will contain a pointer to the necessary speak() function for a Dog or Cat object.

Upvotes: 4

Naszta
Naszta

Reputation: 7744

Do something like this in base class:

#include <istream>

using namespace std;

class Animal
{
  friend istream & operator >> ( istream &is, Animal &animal )
  {
    animal.readFromStream(is);
    return is;
  };
protected:
  virtual void readFromStream( istream &is ) = 0;
};

and in derived:

class Dog : public Animal
{
  protected:
    virtual void readFromStream( istream &is )
    {
      // read dog
    };
};

Upvotes: 5

Related Questions