重载基类>>运算符

Overloading >> operator for a base class

本文关键字:gt 运算符 基类 重载      更新时间:2023-10-16

所以我有一个基类Animal,它继承了两个类,分别是cat和dog。这两个类都重新定义了一个纯虚拟方法,它只把猫的"喵"和狗的"汪汪"计数。在我的main函数中,我希望能够做这样的事情:

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

所以这应该算动物说话的功能,但我怎么做呢?另外,我很困惑,如果你不知道动物的类型,那么你怎么能确定使用哪个说话函数,你会使用模板类吗?

在基类中这样做:

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

下面是重写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>>做类似的事情。

还有,我很困惑,如果你不知道动物的类型,那么你怎么能确定使用哪个说话函数,你会使用模板类吗?

这就是动态绑定/多态性背后的思想。aa2是对Animal的派生类型的引用,由于speak()是虚的,因此v-table将包含指向DogCat对象所需的speak()函数的指针。

你不能完全按照自己的想法去做。也就是说,你不能

Animal a;
std::cin >> a;

并期望'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;
  }
}

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示例