Перегрузка >> оператор для базового класса - PullRequest
1 голос
/ 28 ноября 2011

Итак, у меня есть базовый класс Animal, у которого есть 2 класса, которые являются наследниками - это кошка и собака.Оба класса переопределяют чисто виртуальный метод говорить, который просто "мяу" для кошки и "гав" для собаки.В своей основной функции я хочу иметь возможность делать что-то вроде этого:

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);
}

ТАК, это должно следить за функцией речи животных, но как я могу это сделать?Кроме того, я запутался, если вы не знаете тип животного, которое пользователь собирается использовать, тогда как вы можете определить, какую функцию разговора использовать, вы бы использовали шаблонный класс?

Ответы [ 4 ]

5 голосов
/ 28 ноября 2011

Сделайте что-то подобное в базовом классе:

#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;
};

и в производном:

class Dog : public Animal
{
  protected:
    virtual void readFromStream( istream &is )
    {
      // read dog
    };
};
2 голосов
/ 28 ноября 2011

Вот пример переопределения operator<<, которое вызывает публичную функцию-член speak().Если вам нужен доступ к закрытым членам в перегруженном operator<<, сделайте его 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;
}

. Вы должны научиться делать подобное для operator>>.

*.1010 *

Кроме того, я запутался, если вы не знаете тип животного, которое пользователь собирается сгенерировать, тогда как вы можете определить, какую функцию разговора использовать, вы бы использовали шаблонный класс?

Это идея динамического связывания / полиморфизма.a и a2 являются ссылками на производные типы Animal и, поскольку speak() является виртуальным, v-таблица будет содержать указатель на необходимую функцию speak() для объекта Dog или Cat.

1 голос
/ 28 ноября 2011

Вы не можете делать именно то, что вы хотите.То есть вы не можете

Animal a;
std::cin >> a;

и ожидать, что тип «а» изменится.По сути, объекты не являются полиморфными - указатели и ссылки полиморфны.

Зная это, вы можете сделать что-то почти то, что вы хотите:

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

Вы можетеВыполните это путем перегрузки

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

для создания (через new) объекта указанного во время выполнения типа.

Рассмотрим эту программу:

#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;
  }
}
0 голосов
/ 28 ноября 2011

для оператора <<, все нормально </p>

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

для ввода это более сложный, и я не знаю, можете ли вы сделать это напрямую с Animal но вы могли бы построить 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;
    }
};

так что вы можете позвонить

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);
}

РЕДАКТИРОВАТЬ 1 забыл позвонить speak()

РЕДАКТИРОВАТЬ 2 применил его к примеру OP

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...