重载类的流插入(<<<<<")运算符

时间:2015-04-27 00:14:08

标签: c++

它经常被重载为类的朋友函数。有没有什么方法可以作为成员函数重载?

3 个答案:

答案 0 :(得分:6)

  

有没有什么方法可以作为成员函数重载?

假设您有一个班级Foo,并且您想使用:

Foo foo;
std::cout << foo;

不,它不能。

仅当第一个参数是类的对象时,成员函数重载才有效。对于流插入运算符,第一个参数是流,而不是类的对象。

如果您想使用:

Foo foo;
foo << std::cout;

是的,可以将其定义为成员函数。

在涉及派生类的情况下使用时,非成员函数和虚拟成员函数可以组合起来,效果很好。

struct Shape
{
   // Member function that can be overridden by derived classes.
   virtual std::ostream& operator<<(std::ostream& os) const = 0;
};

// Non-member function that makes use of member functions.
std::ostream& operator<<(std::ostream& os, Shape const& shape)
{
   return shape << os;
}

struct Rectangle : public Shape
{
   virtual std::ostream& operator<<(std::ostream& os) const
   {
      // Do the need full to stream a Rectangle.
      // ...
      return os;
   }
};

struct Ellipse : public Shape
{
   virtual std::ostream& operator<<(std::ostream& os) const
   {
      // Do the need full to stream an Ellipse.
      // ...
      return os;
   }
};

用法:

Rectangle r;
Ellipse e;

std::cout << r << std::endl;
std::cout << e << std::endl;

答案 1 :(得分:0)

  

有没有什么方法可以作为成员函数重载?

没有。该功能的签名会阻止此选项。

// Binary operator where the stream object is left of '<<' and the object
// instance is right of '<<'
std::ostream& operator<<(std::ostream& lhs, const Foo& rhs)

为了说明这里的二元运算符+作为自由函数:

class Foo
{
};

Foo operator+(const Foo& lhs, const Foo& rhs)
{
    // an appropriate implementation
}

int main()
{
    Foo f1;
    Foo f2;

    // Uses the free function
    Foo result = f1 + f2;

    return 0;
}

但是作为成员函数实现它看起来像这样:

class Foo
{
public:
    Foo operator+(const Foo& other) const
    {
        // an appropriate implementation
    }
};

int main()
{
    Foo f1;
    Foo f2;

    // The calling sequence is the same as before however 'f1' is logically
    // the same as 'lhs' in the free function implementation example (i.e.,
    // the first type in the binary operator must be the class type when
    // implemented as a member function)
    Foo result = f1 + f2;

    return 0;
}

给定operator+成员函数示例,更容易理解为什么std::ostream& operator<<(std::ostream& lhs, const Foo& rhs)自由函数无法转换为等效成员函数。因为&#39; lhs&#39;将需要与std::ostream相同的类型,但这只有在实现该类时才有可能,而在此示例中正在实现Foo类。

答案 2 :(得分:0)

如果你想要足够严重,你可以使用成员函数重载,但它直接违反惯例,所以这样做会导致混淆。它还可以防止链接提取/插入操作符,并且不能用于读/写原始类型。

这背后的原因是调用作为成员函数重载的运算符意味着x << y;被解释为x.operator<<(y);,因此重载的运算符必须是左操作数的成员,而不是右边的操作数的成员。有可能这样做(iostream包含某些类型的重载),但它基本上不可能扩展(当它是左操作数时,所有这些重载都必须是iostream对象的一部分)。

如果要将其作为要读取/写入的对象的成员重载,则需要将读取/写入的对象作为左操作数。这意味着插入将从左到右而不是从右到左。为了保持理智至少有一些机会,你几乎肯定希望使用>>进行插入,并使用<<进行提取:

class my_class {
    int x;
public:
    bool operator<<(std::istream &is) { 
        // Note the reversal here. That's because we're defining this 
        // for a `my_class` on the left, and an iostream on the right, 
        // but the existing `>>` and `<<` use the reverse of that (iostream
        // on the left).
        is >> x;
        return is.good();
    }
    bool operator>>(std::ostream &os) { 
        os << x;
        return os.good();
    }
};

my_class a;

a >> std::cout;

a << std::cin;

注意:我只提供 这个答案,指出技术上可以做到这一点,并说明如何做。如果你重新开始使用一个干净的平板并且真的设置使用成员函数,我可以看到可能可以选择这种方法 - 但即便如此,它也是对很多问题持开放态度。

特别是(如上所述)这不支持链接。由于插入和提取是作为左操作数的成员函数完成的,这也意味着它只适用于用户定义的类型,而不适用于任何基本类型(int,short,long,float,double,bool等)

底线:如果你想要足够严重,你可以在有限的情况下让它在有限的程度上工作 - 但既不好(没有链接)也不普遍(没有原始类型)。