我有以下问题:让我们说类Item
包含产品的序列号,
类Book
是Item
,它继承了类Item
的序列号。我必须为每个班级创建并使用operator>>
。我考虑过创建operator>>
到Item
,然后在本书的istream
的实现中调用它,但我不知道如何。
代码如下:
class Item
{
protected:
int _sn;
public:
Item();
~Item();
...
const istream& operator>>(const istream& in,const Item& x)
{
int temp;
in>>temp;
x._sn=temp;
return in;
}
};
class Book
{
private:
char _book_name[20];
public:
Book();
~Book();
...
const istream& operator>>(const istream& in,const Book& x)
{
char temp[20];
////**here i want to use the operator>> of Item**////
in>>temp;
strcpy(x._book_name,temp);
return in;
}
};
int main()
{
Book book;
in>>book; //here i want to get both _sn and _book_name
}
这甚至可能吗?
答案 0 :(得分:10)
首先,operator>>
必须是自由函数或friend
,因为左侧不是您的类类型。其次,lhs也必须是非const引用(因为流在提取时改变状态),第二个参数也是如此(你改变状态,它需要是非const)。考虑到这一点,以下是运营商的看法:
class Item
{
protected:
int _sn;
public:
Item();
~Item();
// ...
friend std::istream& operator>>(std::istream& in, Item& item){
return in >> item._sn;
}
};
class Book
: public Item
{
private:
std::string name;
public:
Book();
~Book();
// ...
friend std::istream& operator>>(std::istream& in, Book& book){
Item& item = book;
return in >> item >> book.name;
}
};
请注意,我将您的C风格字符串处理(char name[20]
+ strncpy
)更改为std::string
,这是您应该在C ++中执行的操作。
如果您只是实施from_stream
方法,则可以更轻松地完成:
class Item
{
protected:
int _sn;
public:
Item();
~Item();
// ...
virtual void from_stream(std::istream& in){
in >> _sn;
}
};
std::istream& operator>>(std::istream& in, Item& item){
item.from_stream(in);
return in;
}
class Book
: public Item
{
private:
std::string name;
public:
Book();
~Book();
// ...
void from_stream(std::istream& in){
Item::from_stream(in);
in >> name;
}
};
感谢from_stream
为virtual
,您永远不需要重新实现operator>>
,它会自动调度到正确的派生类,具体取决于调用它:
int main(){
Item item;
Book book;
std::cin >> item; // calls operator>>(std::cin, item), them item.from_stream(std::cin)
std::cin >> book; // calls operator>>(std::cin, book), converting book to its baseclass Item
// then calls Book::from_stream(std::cin), which in turn calls Item::from_stream(std::cin)
}
答案 1 :(得分:2)
如果要重用派生的基类中定义的运算符,只需在派生声明中添加:
using Base::operator>>;
答案 2 :(得分:2)
简单,不,不直接。 operator>>
只能是流对象的成员函数。对于普通对象,它应该是一个自由函数。如果将其定义为成员函数,则其作为成员函数的类将有效地成为左操作数,而另一个参数成为右操作数。您不能拥有属于成员的两个操作数形式。
可以在operator>>
的实现中使用虚函数来获取operator>>
的多态行为,例如
class Base {
public:
/* ... */
virtual void FromStream(std::istream& is);
/* ... */
};
class Derived : public Base {
/* ... */
virtual void FromStream(std::istream& is);
/* ... */
};
std::istream& operator>>(std::istream& is, Base& base) {
base.FromStream(is);
return is;
}
答案 3 :(得分:1)
你基于这样的方法:
void Derived::foo(args) {
Base::foo(args);
}
// or
class Derived : public Base {
int operator<<(int a) {
Base::operator<<(a);
}
}
Base
是特定基类的名称(您需要指定它,因为可能有更多的直接或间接基类)。
::
是“范围运算符”。这意味着“从operator<<
”范围内调用函数Base
。
上面的内容可能对你有用,但是对于这个特定的操作符和这种情况,(正如@Xeo指出的那样,谢谢!)操作符应该被定义为一个自由函数(也许是一个朋友函数) ),而不是成员函数,因为当您希望它将此类的对象作为其第一个参数(左操作数)时,您只将operator<<
或operator>>
定义为成员函数。
如果在流的上下文中有<<
和>>
,则传统上左操作数是流,因此您需要为此运算符提供一个自由函数(ostream
的成员函数也可以工作,但你必须修改ostream
,你不想尝试。)