Are operator overloads in C ++ more complicated than they cost?

In my C ++ learning experience, operator overloading is one of those topics that causes the most grief for students. Even considering the questions here in stackoverflow: for example, make the + operator external or member? How to deal with symmetry, etc., It seems that this is a lot of trouble.

When I switched from C ++ to Java, I was worried that I would miss this ability, but with the exception of operators such as [] or (), I never felt the need to overload operators. In fact, I feel that programs without them are more readable.

Note. I put this as a community wiki. Let's discuss it. I want to hear opinions.

+6
c ++ operator-overloading
source share
14 answers

Overloaded operators are like spices. A little can do something better; too much can make it unpleasant.

+38
source share

Some examples of overloads that every C ++ programmer should know about, even if they do not approve:

  • operator = () is required in order to allow C ++ objects to behave like values.
  • operator โ†’ () is required to implement smart pointers. Operator
  • <<() and the operator โ†’ () are needed to integrate types into the iostream structure. Operator
  • <() is used by default when comparing objects stored in containers of the standard library.
  • operator () () is used to implement functors used by standard library algorithms
  • The ++ () operator is expected to be available if you implement your own iterator
+30
source share

As simple as complaining about overloaded operators, if they donโ€™t work in amazing ways, I really donโ€™t see the problem. Yes, there are bad examples (even in stl). See For example, the assignment operator auto_ptr. Overloading some operators, such as && , || and , almost always will be bad. But for the most part, getting operators to do what they advertise is no real problem.

It's a good practice to overload operator+ to do something weird, but it's just as bad if you put a method called Add in your class that serialized the object to disk.

+14
source share

Overloaded operators are potentially great ways to do certain things, but it's terribly easy to abuse.

Overloading the << and >> operators simplifies the expansion of C ++ streams both in new types of streams, and in new objects for input-output and both. Overloading -> makes smart pointers almost a replacement for pointers in C ++. Overloaded operators allow you to have a string concatenation operator and create new types of numbers that are syntactically similar to int s. Their presence allows you to do things in libraries, which will require changes at the language level in other languages.

They have their limitations. There is no operator for exponentiation. There is only one multiplication operator, and in some cases there is more than one method of multiplication (for example, with 3D vectors, there are at least point and cross products there). Operators && , || and comma cannot replicate their built-in functions because they cannot have short circuit ratings and sequence points.

And, of course, they can be abused. There is no language requirement, for example, that arithmetic operators should work like arithmetic. I saw terrible things done to come up with an SQL notation that someone thought was intuitive. In a program written poorly written in C ++, it is impossible to understand that, say, a = x * y; , since this is a.operator=(x.operator*(y)); or maybe a.operator=(operator*(x, y)); or something else, and operator functions can be written for anything.

Bjarne Stroustrup's goal in developing C ++ was to include useful functions, regardless of the possibility of abuse, while James Gosling's goal in developing Java was to eliminate overly irreconcilable functions, even if they were somewhat useful. It is not clear to me that any of these philosophies is right or wrong, but they are different.

Java was designed to avoid situations that usually cause some C ++ functions, such as operator overloading, multiple inheritance, and subtraction of the runtime type, so they are often not missed. Whether it is good or bad, or I do not know anything.

Regarding student learning, tell them not to overload the operators themselves (with the exception of certain conditions, such as functors and assignment operators), but to indicate how the library uses overloaded operators. I would not trust a single C ++ student to do everything right, and if they can do it, they can and will study it themselves. They will know this is difficult because you have banned him in the classroom. Some of those that I would never trust anything more difficult than the for statement will learn how to overload the operators and will do it anyway, but what life is.

+6
source share

Operator overloading is quite important for many purposes. Functors cannot be created without the ability to overload operator (). General programming in many cases will be a pain in the butt. If I write a numerical algorithm, I rely on a value type that behaves the same, be it float, double, std :: complex, or some kind of home type. I rely on the usual arithmetic operators that are defined, and such, so I do not need to write a separate overload for the built-in types, and another for the custom ones.

Smart pointers rely on objects that can overload the dereference operator so that they can behave like pointers.

Operator overloading is extremely important to ensure compatibility with C ++. As for complexity, I just don't see it. This is no more complicated than creating your own function, which people usually find quite easily. If you call it "multiply", this is a function, if you call it "operator *", it is an operator. But the code in the body is the same.

Of course, operators are sometimes abused. <or โ†’ may be acceptable at the border, but they are so widely known and used that I think it is fair.

If you asked about operator overloading in something like C #, I would love to go around without them. Their implementation is much more inconvenient, they do not work with generics, and they do not allow you to use all the pleasant and convenient tricks that C ++ uses.

+5
source share

I think it really depends on the use case. There are several types of classes that require operators. For example, smart pointers would be useless without the โ†’ and * operators.

I also find that comparison, equality, and assignment operations are very useful for certain types. I work in the editorโ€™s environment, and therefore, of course, we present the coordinates and intervals several times. Of course, we could do everything with the comparison operator, but

 if ( point1 > point2 ) ... 

It just looks better than

 if ( point1.Compare(point2) < 0 ) ... 

I find less use for other operators, although it is sometimes useful.

+4
source share

I don't think operator overloading was a bad idea. I think creating an implicit default transformation was a bad idea. And the default implicit conversion coupled with operator overloading is a bad idea indeed .

Distract the implicit conversion completely - or make it dependent on the "implicit" keyword - and the language would never have the number of potential pitfalls and errors discussed in countless articles such as this one .

+3
source share

As Neal points out in his answer, operator overloading is a necessary topic to learn about good object-oriented C ++ idioms. I would teach it with caution to students that if you do not implement overloaded operators following idiomatic conventions, this can lead to very bad and unexpected behavior. Overloading the operator is not a good time for creativity.

+2
source share

Operators and cases when I used them:
operator->, operator * - for proxy objects and different shells.
operator = - necessary to prevent unexpected behavior when copying.
operator <(>, <=,> =) - to save on a map or set (but usually it is better to pass a functor to this one)
The operator <(โ†’) is for streams and boost :: lexical_cast compatibility.
operator ==,! = - in order to compare objects. operator! - sometimes instead of the function valid ().
Type operator - to convert to another type.
operator () - for a smart functor when boost was disabled.

what all.
Sometimes I used other operators, but that was for my math applications.

You should also be careful with the logical operators (& &, ||) - we will have a difference with the standard semantics:

 ptr && ptr->method() 

may have a different meaning if we have an overloaded operator &. </p>

+1
source share

I really like the ability to overload arithmetic operators for non-line types in C ++. But only for types with arithmetic-like behavior; for example, fixed-point classes, three-dimensional vector classes, classes of complex numbers, classes of arbitrary length "bignum". I wrote similar code in Java and was annoyed that instead of a+b wrote things like a.Add(b) . Keep in mind I am a mathematician by education; It seems to me that overloading operators allows you to get a little quality factor at the domain level in C ++, without actually having it implemented.

But it really annoys me when I see, for example, that operator+ overloaded with functionality that would be better done with operator<< (after a dodgy but well-established agreement on iostream) or STL .push_back() -like templates.

As for operator() ... after detecting boost::bind and boost::function , I cannot imagine life without functors. And smart pointers would not be nearly convenient without overloaded operator* , operator-> etc.

+1
source share

The problem with overload operators is that some people like to overload them with functionality, which actually makes no sense with the original (C) goal of the operator (here I point to โ†’ and <<<<<<<<, the statements in the file std :: iostream.). In my opinion, the only time you have to overload operators is when ever overloading EXACTLY matches the value of the base operator (i.e., <and> should be comparisons). OR, you must overload it in a certain way in order to interact with another library.

Frankly, I will not overload the operator at all if I do not need a library. It just makes the reader work too hard to understand what is going on.

0
source share

One operator to avoid overloading is the conversion operator . This leads to such unexpected results that even STL prefers not to overload it and instead prefers function style conversion:

 std::string str = "foo"; char *ch = str.c_str(); //rather than char *ch = str.operator *char(); 
0
source share

I miss the overloaded operators in Java, especially in the following situations:

A class that is an algorithm or functor: (Strategy template, chain of responsibility, translator, etc.). Overloading op () is natural; instead, each programmer comes up with (often incompatible and thus confusing) names for the functions: "eval", "rating", "operation", "doIt", etc. Thus, clarity is reduced, because these names we are forced to use do not make their meaning obvious.

A class that has a conversion to another type: In C ++, this Type () operator works both for the actual conversion, and for getting the internal member of the desired class. In the second case, a lot of things happen in Java when the class is unnecessarily final, but you want to add operations to it:

 class DecoratedStringBuffer { //extends StringBuffer doesn't work, as String is final private String byContainmentThen; public decorate(final String prefix, final String suffix) { ... } public append(final String s) { byContainmentThen.append(s);} // other forwarding functions } 

Since DecoratedStringBuffer is not -StringBuffer, before it leaves your code and returns to the client code, it needs to be converted back, presumably using a function that ultimately applies the suffix and prefix. It would be great if we could name this operator StringBuffer () (and even more if Java, for example C ++, can apply one user-defined transformation).

Instead, since there is no agreement, we must give it a name that is necessarily more ambiguous. getStringBuffer () is one obvious name, but for many Java users, which implies the corresponding setStringBuffer, which we do not need. Even if this does not mean that the name is ambiguous: is it the StringBuffer you are working with, or something else?

toStringBuffer () is the best name and template that I usually use, but then someone reading the code wonders why what looks like getter is called "in" ClassName.

Honestly, in addition to designing numerical classes or "explicitly" co-objects, it is little used for op + overloading. And since Java is not value-based like C ++, there is very little use for op =; Java does not try to make everything act as a primitive class of int values. These are op () and conversion operators, which I skip.

0
source share

It's nice to have a feature, but not a very important one. In many cases, I find them more confusing than the benefits they have. Like the JaredPars example, the .compare function is more obvious than the ">" for me. It can be seen that point1 is an object, not a primitive data type. I like the overloaded operators in libs that I use, but in my own code I use them very rarely.

EDIT: my choice of function name is inconsistent. Replace .compare with .greaterThan, it will become more clear. I mean, the name of the function attached to the object is more obvious to me than the operator, which does not associate with the object at first glance. Imho a well-chosen function name is easier to read.

-one
source share

All Articles