我可以继承运算符>>?

时间:2011-12-31 11:17:59

标签: c++

我有以下问题:让我们说类Item包含产品的序列号, 类BookItem,它继承了类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
}

这甚至可能吗?

4 个答案:

答案 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_streamvirtual,您永远不需要重新实现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,你不想尝试。)