我有类Person(名字,姓氏,地址,年龄)和重载运算符<<和>>与文件流一起使用:
ostream& operator<< (ostream& outStream, Person& person)
{
...
}
istream& operator>> (istream& inStream, Person& person)
{
...
}
它工作正常 - 我可以轻松地读取和写入文件,但我添加了两个继承自Person:Student和Worker的类。
我为他们编写了重载操作符,与上面的操作符非常相似:
ostream& operator<< (ostream& outStream, Worker& worker)
{
...
}
istream& operator>> (istream& inStream, Worker& worker)
{
...
}
ostream& operator<< (ostream& outStream, Student& student)
{
...
}
istream& operator>> (istream& inStream, Student& student)
{
...
}
唯一不同的是每个班级还有两个字段。问题是,当我使用Student或Worker重载运算符时,我的编译器似乎使用运算符。可能它会从Student或Worker到Person进行隐藏转换,但结果是没有写入该文件的其他字段。 offstream&lt;&lt;人们的工作方式与offstream&lt;&lt;学生或工人。 也许首先为继承的类放置重载的运算符声明,然后在代码中为Person解决问题,但我不认为它是一个优雅的解决方案。
如果您对如何解决上述问题有一些想法,我将不胜感激。
答案 0 :(得分:12)
两件事。首先,让你的运算符接受const的引用,如下所示:
ostream& operator<< (ostream& outStream, const Person& person)
要解决您的问题,常见的模式是为您的类型提供受保护的虚拟toString
方法,并让操作员调用它。然后,您可以在子类中重载此方法,如果您只想在字符串中附加一些值,甚至可以重用超类实现。
示例:
class Person {
// other stuff
protected:
virtual std::string toString();
friend ostream& operator<< (ostream& outStream, const Person& person)
};
ostream& operator<< (ostream& outStream, Person& person)
{
ostream << person.toString();
return outStream;
}
修改强> 实际上,我更喜欢larsmans的建议:
class Person {
// other stuff
protected:
virtual void print(ostream & stream) const;
friend ostream& operator<< (ostream& outStream, const Person& person)
};
ostream& operator<< (ostream& outStream, Person& person)
{
person.print(outStream);
return outStream;
}
这比toString
想法更容易实现,因为您不需要临时stringstream
或类似的东西来构建字符串。
答案 1 :(得分:3)
调用<<
运算符的代码很可能通过指向 Person 的指针或引用来访问对象,从而调用 Person 类型的运算符。处理此问题的常用方法是在父类(即 Person )类上提供虚拟方法,该类执行写入(将流作为参数),并让operator<<
调用此方法做工作的方法。您只需要为父类提供operator<<
,虚拟调度机制将负责为所提供的对象选择正确的方法。
class Person {
// ...
protected:
virtual ostream& stream_write(ostream&) const; //override this in child classes
virtual istream& stream_read(istream&); //this too
public:
friend ostream& operator<< (ostream& stream, const Person& obj)
{ return obj.stream_write(stream); }
friend istream& operator>> (istream& stream, Person& obj)
{ return obj.stream_read(stream); }
};
答案 2 :(得分:2)
您的操作员可以调用虚拟方法。像这样:
struct A
{
virtual ~A(){}
virtual std::ostream& Print( std::ostream &os ) const
{
// print what you want
return os;
}
};
struct B : A
{
virtual ~B(){}
virtual std::ostream& Print( std::ostream &os ) const
{
// print what you want
return os;
}
};
然后创建运算符&lt;&lt;仅适用于基类:
std::ostream& operator<<( std::ostream &os, const A &a)
{
return a.Print(os);
}
答案 3 :(得分:0)
我通常在重载的流操作符中调用虚函数streamIn和streamOut,这样我实际上可以创建一个模板流函数,该函数适用于所有具有streamIn和streamOut函数的类。