所以我有一个基类Animal,它有两个继承自它的类,它们是猫和狗。这两个课程都重新定义了一种纯粹的虚拟方法,这种方法只会为猫猫咪“喵喵叫”,为狗提供“低音”。在我的主要功能中,我希望能够做到这样的事情:
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);
}
所以这应该让动物说出功能,但我怎么能这样做呢?另外,我很困惑,如果你不知道用户将要使用的动物类型,那么你如何确定使用哪种语音功能,你会使用模板类吗?
答案 0 :(得分:5)
在基类中执行类似的操作:
#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
};
};
答案 1 :(得分:2)
以下是覆盖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>>
进行类似操作。
另外,我很困惑,如果你不知道用户打算使用的动物类型,那么你如何确定使用哪种说话功能,你会使用模板类吗?
这是动态绑定/多态的背后的想法。 a
和a2
是对Animal
的派生类型的引用,由于speak()
是虚拟的,因此v表将包含指向必要speak()
函数的指针对于Dog
或Cat
对象。
答案 2 :(得分:1)
你无法准确地做到你想要的。也就是说,你不能
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;
}
}
答案 3 :(得分:0)
用于&lt;&lt;运营商,有点好吗
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示例