0

在 C++ 中重载运算符的主要目的是什么?

在下面的代码中,<<并且>>被重载;这样做有什么好处?

#include <iostream>
#include <string>

using namespace std;

class  book {
    string name,gvari;
    double cost;
    int year;
    public:
    book(){};

    book(string a, string b, double c, int d) { a=name;b=gvari;c=cost;d=year; }
    ~book() {}
    double setprice(double a) { return a=cost; }
    friend ostream& operator <<(ostream& , book&);
    void printbook(){
        cout<<"wignis saxeli "<<name<<endl;
        cout<<"wignis avtori "<<gvari<<endl;
        cout<<"girebuleba "<<cost<<endl;
        cout<<"weli "<<year<<endl;
    }
};

ostream& operator <<(ostream& out, book& a){
    out<<"wignis saxeli "<<a.name<<endl;
    out<<"wignis avtori "<<a.gvari<<endl;
    out<<"girebuleba "<<a.cost<<endl;
    out<<"weli "<<a.year<<endl;
    return out;
}

class library_card : public book {
    string nomeri;
    int raod;
    public:
    library_card(){};
    library_card( string a, int b){a=nomeri;b=raod;}
    ~library_card() {};
    void printcard(){
        cout<<"katalogis nomeri "<<nomeri<<endl;
        cout<<"gacemis raodenoba "<<raod<<endl;
    }
    friend ostream& operator <<(ostream& , library_card&);
};

ostream& operator <<(ostream& out, library_card& b) {
    out<<"katalogis nomeri "<<b.nomeri<<endl;
    out<<"gacemis raodenoba "<<b.raod<<endl;
    return out;
}


int main() {
    book A("robizon kruno","giorgi",15,1992);
    library_card B("910CPP",123);
    A.printbook();
    B.printbook();
    A.setprice(15);
    B.printbook();

    system("pause");
    return 0;
}
4

8 回答 8

7

它永远不必使用;这只是一种方便,一种让用户定义类型更像内置类型的方式。

例如,如果重载 operator<<,则可以像整数和字符串一样流式传输书籍:

cout << "Book #" << n << " is " << books[n] << endl;

如果你不这样做,你必须写这样的相同的东西:

cout << "Book #" << n << " is ";
books[n].printbook();
cout << endl;

类似地,如果你创建一个 Fraction 类并给它一个 operator+,你可以像使用整数一样使用分数,等等。

有时,您的类是否应该以某种方式表现得像本机类型(例如,字符串的 operator+ 有意义吗?),有时是一个艰难的设计选择,但关键是 C++ 为您提供了选择。

于 2012-06-15T22:02:59.610 回答
2

重载<<运算符允许您的对象在传递给 cout 时以您指定的方式写入输出。

否则, cout 只会写出你的对象的地址。

于 2012-06-15T22:02:44.710 回答
2

重载运算符的目的主要是语法糖。它使丑陋的东西看起来不错。但它也是关于统一接口的,统一接口的一个重要原因是多态性,在这种情况下尤其是模板。

想象一下,我们有一个可爱的复数类Complex,我们想要一个正弦的泰勒级数逼近,我们想要为 Complex 和 double 类型工作。

如果我们支持运算符重载 on *,等=/那么我们可以这样写:

template<typename T>
T sin(T t)
{
  T t2 = t*t;
  return t*(1 - t2/6 + (t2*t2)/120 );
}

如果我们不能在等上重载*/那么它开始变得丑陋,因为我们需要一个帮助类来统一双精度和复杂的接口,这就是它的样子。(我仍然允许重载operator=,否则会变得更糟)。

template<typename T>
T sin(T t)
{
  T t2 = helper<T>::mult( t, t );
  T t4 = helper<T>::mult( t2, t2 );
  T s(1);
  helper<T>::sincrement( &s, -1./6, t2);
  helper<T>::sincrement( &s, -1./120, t4);
  return helper<T>::mult( t, s );
}

template<>
struct helper<double>
{
  static double mult( double a, double b) { return a*b; }
  static void sincrement( double * v, double s, double x) { *v += s*x; }
}

template<>
struct helper<Complex>
{
  static Complex mult( Complex a, Complex b ) { return a.mult(b); }
  static void sincrement( Complex * v, double s, Complex x ) { v->add( x.scale(s) ); }
}

现在我知道运算符重载可能很丑陋,并且可以隐藏真正发生的事情,但正确使用我认为它使这样的情况更容易理解。

于 2012-06-23T00:56:24.813 回答
1

The thing about C++ is it passes objects by value, as a fundamental aim of how it works, and this really greatly changes how objects work compared to reference-semantics oriented languages like Java and Objective-C.

Whereas in one of those languages there is a clear distinction between primitive types and objects in terms of how you use them - that is, you copy primitives a lot, you stick them into expressions involving operators, that sort of thing, whereas your interaction with objects is mainly instantiating them, calling methods on them and passing the references to them into functions - in C++ you can use objects pretty much the same way as you use primitives. This brings up a lot of complicated issues that C++ programmers have to deal with, like object lifetimes, whether an object is an lvalue or rvalue (that is, if it has a lifetime outside the expression it appears in), etc.

One thing your question brings up is why a class would overload << and >>. The C++ standard library uses this convention for iostream classes, and highlights another big difference from reference-semantics based languages - in a value-semantics oriented language, class inheritance is inadequate to fully describe what you want to do with an object. We can loosely say that if an object overloads << and >> to stream data in and out of some resource, then it satisfies the concept of an iostream, even if it doesn't inherit from iostream, or ios_base, or something. The meaning of this is twofold:

  1. If you put a value of this type into an expression and used <<, it would behave as expected.
  2. If you instantiate a template with this type as a parameter, which calls operator<< on the object, the code will compile successfully.

I deliberately used the word concept above because there was going to be a feature in C++11 (it got postponed to the next version) called Concepts which would formalise this idea in the language. The situation we have now is a sort of duck typing - if a template wants to use a certain operator with a type, it will compile if the type provides that operator and won't if it doesn't, regardless of what the operator actually means. operator<< is a case in point - in its original meaning, for an integer type, it means "leftward signed bit-shift", but when you are using the concept of iostream, it means "stream data from the object on the right into the object to the left".

于 2012-06-18T09:46:04.263 回答
1

您可以轻松地使用成员函数,在大多数情况下它只是提供“语法糖”。例如,在某些语言中,添加 2 个字符串会执行 concat。

stringOne = stringOne + stringTwo;

虽然它可以很容易地用一个成员函数来实现,比如

stringOne.concat(stringTwo);
于 2012-06-15T22:02:13.260 回答
1

重载运算符允许多态的特殊情况。

我能想到的最好的例子是重载了 + 运算符的字符串类。

在这种情况下,运算符将被重载以连接字符串,而不是“添加”两个没有任何意义的字符串。

为了回答您的问题,重载运算符可以(在某些情况下)生成更具可读性和可维护性的代码。然而,对一个人“有意义”的东西对于维护代码的人可能没有意义。

于 2012-06-15T22:03:08.900 回答
1

使用重载运算符,您可以使用要求该运算符重载的标准库算法。

例如:

struct wtf{ wtf(int omg): omg(omg){} int omg; };

wtf operator+ (wtf const &omg, wtf const &lol)
{
    return wtf(omg.omg+ lol.omg);
}

#include <iostream>
#include <numeric>

int main()
{
    wtf lol[3]= { wtf(1), wtf(2), wtf(3) };
    std::cout<< std::accumulate(lol, lol+ 3, wtf(0)).omg;
}

6

于 2012-06-18T08:10:13.810 回答
0

您重载 << 和 >> 运算符的主要目的是按照 C++ 标准库的精神创建一个 API,因此有经验的 C++ 程序员使用您的类型变得更加自然。

正是这样,操作符 << 和 >>在与 STL 流一起使用时称为插入/提取操作符。从 C 开始,它们只是位移运算符

由于在标准 C++ 领域中,他们获得了该含义,甚至为此获得了新的命名法,因此重用已经建立的编程术语是件好事。

现在,最初在 C++ 的创建中,为什么它对流操作采取了这种方式?通过获取移位运算符并将它们标记为插入和提取运算符,我不知道,考虑到移位运算符的出现,这可能是为了更好地表达插入/提取的想法,这个含义现在已经成为标准和西装可以重复使用。

于 2012-06-15T22:04:59.890 回答