• Sign In / Suggest an Article

Current ISO C++ status

Upcoming ISO C++ meetings

Upcoming C++ conferences

Compiler conformance status

CppCon 2024

September 15-20, Aurora, CO, USA

Meeting C++ 2024

November 14-16, Berlin, Germany

operator overloading

Operator overloading, what’s the deal with operator overloading.

It allows you to provide an intuitive interface to users of your class, plus makes it possible for templates to work equally well with classes and built-in/intrinsic types.

Operator overloading allows C/C++ operators to have user-defined meanings on user-defined types (classes). Overloaded operators are syntactic sugar for function calls:

What are the benefits of operator overloading?

By overloading standard operators on a class, you can exploit the intuition of the users of that class. This lets users program in the language of the problem domain rather than in the language of the machine.

The ultimate goal is to reduce both the learning curve and the defect rate.

What are some examples of operator overloading?

Here are a few of the many examples of operator overloading:

  • myString + yourString might concatenate two std::string objects
  • myDate++ might increment a Date object
  • a * b might multiply two Number objects
  • a[i] might access an element of an Array object
  • x = *p might dereference a “smart pointer” that “points” to a disk record — it could seek to the location on disk where p “points” and return the appropriate record into x

But operator overloading makes my class look ugly; isn’t it supposed to make my code clearer?

Operator overloading makes life easier for the users of a class , not for the developer of the class!

Consider the following example.

Some people don’t like the keyword operator or the somewhat funny syntax that goes with it in the body of the class itself. But the operator overloading syntax isn’t supposed to make life easier for the developer of a class. It’s supposed to make life easier for the users of the class:

Remember: in a reuse-oriented world, there will usually be many people who use your class, but there is only one person who builds it (yourself); therefore you should do things that favor the many rather than the few.

What operators can/cannot be overloaded?

Most can be overloaded. The only C operators that can’t be are . and ?: (and sizeof , which is technically an operator). C++ adds a few of its own operators, most of which can be overloaded except :: and .* .

Here’s an example of the subscript operator (it returns a reference). First with out operator overloading:

Now the same logic is presented with operator overloading:

Why can’t I overload . (dot), :: , sizeof , etc.?

Most operators can be overloaded by a programmer. The exceptions are

There is no fundamental reason to disallow overloading of ?: . So far the committee just hasn’t seen the need to introduce the special case of overloading a ternary operator. Note that a function overloading expr1?expr2:expr3 would not be able to guarantee that only one of expr2 and expr3 was executed.

sizeof cannot be overloaded because built-in operations, such as incrementing a pointer into an array implicitly depends on it. Consider:

Thus, sizeof(X) could not be given a new and different meaning by the programmer without violating basic language rules.

What about :: ? In N::m neither N nor m are expressions with values; N and m are names known to the compiler and :: performs a (compile time) scope resolution rather than an expression evaluation. One could imagine allowing overloading of x::y where x is an object rather than a namespace or a class, but that would – contrary to first appearances – involve introducing new syntax (to allow expr::expr ). It is not obvious what benefits such a complication would bring.

operator. (dot) could in principle be overloaded using the same technique as used for -> . However, doing so can lead to questions about whether an operation is meant for the object overloading . or an object referred to by . . For example:

This problem can be solved in several ways. So far in standardization, it has not been obvious which way would be best. For more details, see D&E .

Can I define my own operators?

Sorry, no. The possibility has been considered several times, but each time it was decided that the likely problems outweighed the likely benefits.

It’s not a language-technical problem. Even when Stroustrup first considered it in 1983, he knew how it could be implemented. However, the experience has been that when we go beyond the most trivial examples people seem to have subtly different opinions of “the obvious” meaning of uses of an operator. A classical example is a**b**c . Assume that ** has been made to mean exponentiation. Now should a**b**c mean (a**b)**c or a**(b**c) ? Experts have thought the answer was obvious and their friends agreed – and then found that they didn’t agree on which resolution was the obvious one. Such problems seem prone to lead to subtle bugs.

Can I overload operator== so it lets me compare two char[] using a string comparison?

No: at least one operand of any overloaded operator must be of some user-defined type (most of the time that means a class ).

But even if C++ allowed you to do this, which it doesn’t, you wouldn’t want to do it anyway since you really should be using a std::string -like class rather than an array of char in the first place since arrays are evil .

Can I create a operator** for “to-the-power-of” operations?

The names of, precedence of, associativity of, and arity of operators is fixed by the language. There is no operator** in C++, so you cannot create one for a class type.

If you’re in doubt, consider that x ** y is the same as x * (*y) (in other words, the compiler assumes y is a pointer). Besides, operator overloading is just syntactic sugar for function calls. Although this particular syntactic sugar can be very sweet, it doesn’t add anything fundamental. I suggest you overload pow(base,exponent) (a double precision version is in <cmath> ).

By the way, operator^ can work for to-the-power-of, except it has the wrong precedence and associativity.

The previous FAQs tell me which operators I can override; but which operators should I override?

Bottom line: don’t confuse your users.

Remember the purpose of operator overloading: to reduce the cost and defect rate in code that uses your class. If you create operators that confuse your users (because they’re cool, because they make the code faster, because you need to prove to yourself that you can do it; doesn’t really matter why), you’ve violated the whole reason for using operator overloading in the first place.

What are some guidelines / “rules of thumb” for overloading operators?

Here are a few guidelines / rules of thumb (but be sure to read the previous FAQ before reading this list):

  • Use common sense. If your overloaded operator makes life easier and safer for your users, do it; otherwise don’t. This is the most important guideline. In fact it is, in a very real sense, the only guideline; the rest are just special cases.
  • If you define arithmetic operators, maintain the usual arithmetic identities. For example, if your class defines x + y and x - y , then x + y - y ought to return an object that is behaviorally equivalent to x . The term behaviorally equivalent is defined in the bullet on x == y below, but simply put, it means the two objects should ideally act like they have the same state. This should be true even if you decide not to define an == operator for objects of your class.
  • You should provide arithmetic operators only when they make logical sense to users. Subtracting two dates makes sense, logically returning the duration between those dates, so you might want to allow date1 - date2 for objects of your Date class (provided you have a reasonable class/type to represent the duration between two Date objects). However adding two dates makes no sense: what does it mean to add July 4, 1776 to June 5, 1959? Similarly it makes no sense to multiply or divide dates, so you should not define any of those operators.
  • You should provide mixed-mode arithmetic operators only when they make logical sense to users. For example, it makes sense to add a duration (say 35 days) to a date (say July 4, 1776), so you might define date + duration to return a Date . Similarly date - duration could also return a Date . But duration - date does not make sense at the conceptual level (what does it mean to subtract July 4, 1776 from 35 days?) so you should not define that operator.
  • If you provide constructive operators, they should return their result by value. For example, x + y should return its result by value. If it returns by reference, you will probably run into lots of problems figuring out who owns the referent and when the referent will get destructed. Doesn’t matter if returning by reference is more efficient; it is probably wrong . See the next bullet for more on this point.
  • If you provide constructive operators, they should not change their operands. For example, x + y should not change x . For some crazy reason, programmers often define x + y to be logically the same as x += y because the latter is faster. But remember, your users expect x + y to make a copy. In fact they selected the + operator (over, say, the += operator) precisely because they wanted a copy. If they wanted to modify x , they would have used whatever is equivalent to x += y instead. Don’t make semantic decisions for your users; it’s their decision, not yours, whether they want the semantics of x + y vs. x += y . Tell them that one is faster if you want, but then step back and let them make the final decision — they know what they’re trying to achieve and you do not.
  • If you provide constructive operators, they should allow promotion of the left-hand operand (at least in the case where the class has a single-parameter ctor that is not marked with the explicit keyword ). For example, if your class Fraction supports promotion from int to Fraction (via the non- explicit ctor Fraction::Fraction(int) ), and if you allow x - y for two Fraction objects, you should also allow 42 - y . In practice that simply means that your operator-() should not be a member function of Fraction . Typically you will make it a friend , if for no other reason than to force it into the public: part of the class , but even if it is not a friend, it should not be a member.
  • In general, your operator should change its operand(s) if and only if the operands get changed when you apply the same operator to intrinsic types. x == y and x << y should not change either operand; x *= y and x <<= y should (but only the left-hand operand).
  • If you define x++ and ++x , maintain the usual identities. For example, x++ and ++x should have the same observable effect on x , and should differ only in what they return. ++x should return x by reference; x++ should either return a copy (by value) of the original state of x or should have a void return-type. You’re usually better off returning a copy of the original state of x by value, especially if your class will be used in generic algorithms. The easy way to do that is to implement x++ using three lines: make a local copy of *this , call ++x (i.e., this->operator++() ), then return the local copy. Similar comments for x-- and --x .
  • If you define ++x and x += 1 , maintain the usual identities. For example, these expressions should have the same observable behavior, including the same result. Among other things, that means your += operator should return x by reference. Similar comments for --x and x -= 1 .
  • If you define *p and p[0] for pointer-like objects, maintain the usual identities. For example, these two expressions should have the same result and neither should change p .
  • If you define p[i] and *(p+i) for pointer-like objects, maintain the usual identities. For example, these two expressions should have the same result and neither should change p . Similar comments for p[-i] and *(p-i) .
  • Subscript operators generally come in pairs; see on const -overloading .
  • If you define x == y , then x == y should be true if and only if the two objects are behaviorally equivalent. In this bullet, the term “behaviorally equivalent” means the observable behavior of any operation or sequence of operations applied to x will be the same as when applied to y . The term “operation” means methods, friends, operators, or just about anything else you can do with these objects (except, of course, the address-of operator). You won’t always be able to achieve that goal, but you ought to get close, and you ought to document any variances (other than the address-of operator).
  • If you define x == y and x = y , maintain the usual identities. For example, after an assignment, the two objects should be equal. Even if you don’t define x == y , the two objects should be behaviorally equivalent (see above for the meaning of that phrase) after an assignment.
  • If you define x == y and x != y , you should maintain the usual identities. For example, these expressions should return something convertible to bool , neither should change its operands, and x == y should have the same result as !(x != y) , and vice versa.
  • If you define inequality operators like x <= y and x < y , you should maintain the usual identities. For example, if x < y and y < z are both true, then x < z should also be true, etc. Similar comments for x >= y and x > y .
  • If you define inequality operators like x < y and x >= y , you should maintain the usual identities. For example, x < y should have the result as !(x >= y) . You can’t always do that, but you should get close and you should document any variances. Similar comments for x > y and !(x <= y) , etc.
  • Avoid overloading short-circuiting operators: x || y or x && y . The overloaded versions of these do not short-circuit — they evaluate both operands even if the left-hand operand “determines” the outcome, so that confuses users.
  • Avoid overloading the comma operator: x, y . The overloaded comma operator does not have the same ordering properties that it has when it is not overloaded, and that confuses users.
  • Don’t overload an operator that is non-intuitive to your users. This is called the Doctrine of Least Surprise. For example, although C++ uses std::cout << x for printing, and although printing is technically called inserting, and although inserting sort of sounds like what happens when you push an element onto a stack, don’t overload myStack << x to push an element onto a stack. It might make sense when you’re really tired or otherwise mentally impaired, and a few of your friends might think it’s “kewl,” but just say No.
  • Use common sense. If you don’t see “your” operator listed here, you can figure it out. Just remember the ultimate goals of operator overloading: to make life easier for your users, in particular to make their code cheaper to write and more obvious.

Caveat: the list is not exhaustive. That means there are other entries that you might consider “missing.” I know.

Caveat: the list contains guidelines, not hard and fast rules. That means almost all of the entries have exceptions, and most of those exceptions are not explicitly stated. I know.

Caveat: please don’t email me about the additions or exceptions. I’ve already spent way too much time on this particular answer.

How do I create a subscript operator for a Matrix class?

Use operator() rather than operator[] .

When you have multiple subscripts, the cleanest way to do it is with operator() rather than with operator[] . The reason is that operator[] always takes exactly one parameter, but operator() can take any number of parameters (in the case of a rectangular matrix, two parameters are needed).

For example:

Then you can access an element of Matrix m using m(i,j) rather than m[i][j] :

See the next FAQ for more detail on the reasons to use m(i,j) vs. m[i][j] .

Why shouldn’t my Matrix class’s interface look like an array-of-array?

Here’s what this FAQ is really all about: Some people build a Matrix class that has an operator[] that returns a reference to an Array object (or perhaps to a raw array , shudder), and that Array object has an operator[] that returns an element of the Matrix (e.g., a reference to a double ). Thus they access elements of the matrix using syntax like m[i][j] rather than syntax like m(i,j) .

The array-of-array solution obviously works, but it is less flexible than the operator() approach . Specifically, there are easy performance tuning tricks that can be done with the operator() approach that are more difficult in the [][] approach, and therefore the [][] approach is more likely to lead to bad performance, at least in some cases.

For example, the easiest way to implement the [][] approach is to use a physical layout of the matrix as a dense matrix that is stored in row-major form (or is it column-major; I can’t ever remember). In contrast, the operator() approach totally hides the physical layout of the matrix, and that can lead to better performance in some cases.

Put it this way: the operator() approach is never worse than, and sometimes better than, the [][] approach.

  • The operator() approach is never worse because it is easy to implement the dense, row-major physical layout using the operator() approach, so when that configuration happens to be the optimal layout from a performance standpoint, the operator() approach is just as easy as the [][] approach (perhaps the operator() approach is a tiny bit easier, but I won’t quibble over minor nits).
  • The operator() approach is sometimes better because whenever the optimal layout for a given application happens to be something other than dense, row-major, the implementation is often significantly easier using the operator() approach compared to the [][] approach.

As an example of when a physical layout makes a significant difference, a recent project happened to access the matrix elements in columns (that is, the algorithm accesses all the elements in one column, then the elements in another, etc.), and if the physical layout is row-major, the accesses can “stride the cache”. For example, if the rows happen to be almost as big as the processor’s cache size, the machine can end up with a “cache miss” for almost every element access. In this particular project, we got a 20% improvement in performance by changing the mapping from the logical layout (row,column) to the physical layout (column,row).

Of course there are many examples of this sort of thing from numerical methods, and sparse matrices are a whole other dimension on this issue. Since it is, in general, easier to implement a sparse matrix or swap row/column ordering using the operator() approach, the operator() approach loses nothing and may gain something — it has no down-side and a potential up-side.

Use the operator() approach .

I still don’t get it. Why shouldn’t my Matrix class’s interface look like an array-of-array?

The same reasons you encapsulate your data structures, and the same reason you check parameters to make sure they are valid.

A few people use [][] despite its limitations , arguing that [][] is better because it is faster or because it uses C-syntax. The problem with the “it’s faster” argument is that it’s not — at least not on the latest version of two of the world’s best known C++ compilers. The problem with the “uses C-syntax” argument is that C++ is not C. Plus, oh yea, the C-syntax makes it harder to change the data structure and harder to check parameter values.

The point of the previous two FAQs is that m(i,j) gives you a clean, simple way to check all the parameters and to hide (and therefore, if you want to, change) the internal data structure. The world already has way too many exposed data structures and way too many out-of-bounds parameters, and those cost way too much money and cause way too many delays and way too many defects.

Now everybody knows that you are different. You are clairvoyant with perfect knowledge of the future, and you know that no one will ever find any benefit from changing your matrix’s internal data structure. Plus you are a good programmer, unlike those slobs out there that occasionally pass wrong parameters, so you don’t need to worry about pesky little things like parameter checking. But even though you don’t need to worry about maintenance costs (no one ever needs to change your code), there might be one or two other programmers who aren’t quite perfect yet. For them, maintenance costs are high, defects are real, and requirements change. Believe it or not, every once in a while they need to (better sit down) change their code.

Admittedly my thongue wath in my theek. But there was a point. The point was that encapsulation and parameter-checking are not crutches for the weak. It’s smart to use techniques that make encapsulation and/or parameter checking easy. The m(i,j) syntax is one of those techniques.

Having said all that, if you find yourself maintaining a billion-line app where the original team used m[i][j] , or even if you are writing a brand new app and you just plain want to use m[i][j] , you can still encapsulate the data structure and/or check all your parameters. It’s not even that hard. However it does require a level of sophistication that, like it or not, average C++ programmers fear. Fortunately you are not average, so read on.

If you merely want to check parameters, just make sure the outer operator[] returns an object rather than a raw array , then that object’s operator[] can check its parameter in the usual way. Beware that this can slow down your program. In particular, if these inner array-like objects end up allocating their own block of memory for their row of the matrix, the performance overhead for creating / destroying your matrix objects can grow dramatically. The theoretical cost is still O( rows × cols ), but in practice, the overhead of the memory allocator ( new or malloc ) can be much larger than anything else, and that overhead can swamp the other costs. For instance, on two of the world’s best known C++ compilers, the separate-allocation-per-row technique was 10x slower than the one-allocation-for-the-entire-matrix technique . 10% is one thing, 10x is another.

If you want to check the parameters without the above overhead and/or if you want to encapsulate (and possibly change) the matrix’s internal data structure, follow these steps:

  • Add operator()(unsigned row, unsigned col) to the Matrix class.
  • Create nested class Matrix::Row . It should have a ctor with parameters (Matrix& matrix, unsigned row) , and it should store those two values in its this object.
  • Change Matrix::operator[](unsigned row) so it returns an object of class Matrix::Row , e.g., { return Row(*this,row); } .
  • Class Matrix::Row then defines its own operator[](unsigned col) which turns around and calls, you guessed it, Matrix::operator()(unsigned row, unsigned col) . If the Matrix::Row data members are called Matrix& matrix_ and unsigned row_ , the code for Matrix::Row::operator[](unsigned col) will be { return matrix_(row_, col); }

Next you will enable const overloading by repeating the above steps. You will create the const version of the various methods, and you will create a new nested class, probably called Matrix::ConstRow . Don’t forget to use const Matrix& instead of Matrix& .

Final step: find the joker who failed to read the previous FAQ and thonk him in the noggin.

If you have a decent compiler and if you judiciously use inlining , the compiler should optimize away the temporary objects. In other words, the operator[] -approach above will hopefully not be slower than what it would have been if you had directly called Matrix::operator()(unsigned row, unsigned col) in the first place. Of course you could have made your life simpler and avoided most of the above work by directly calling Matrix::operator()(unsigned row, unsigned col) in the first place. So you might as well directly call Matrix::operator()(unsigned row, unsigned col) in the first place.

Should I design my classes from the outside (interfaces first) or from the inside (data first)?

From the outside!

A good interface provides a simplified view that is expressed in the vocabulary of a user . In the case of OO software, the interface is normally the set of public methods of either a single class or a tight group of classes .

First think about what the object logically represents, not how you intend to physically build it. For example, suppose you have a Stack class that will be built by containing a LinkedList :

Should the Stack have a get() method that returns the LinkedList ? Or a set() method that takes a LinkedList ? Or a constructor that takes a LinkedList ? Obviously the answer is No, since you should design your interfaces from the outside-in. I.e., users of Stack objects don’t care about LinkedList s; they care about pushing and popping.

Now for another example that is a bit more subtle. Suppose class LinkedList is built using a linked list of Node objects, where each Node object has a pointer to the next Node :

Should the LinkedList class have a get() method that will let users access the first Node ? Should the Node object have a get() method that will let users follow that Node to the next Node in the chain? In other words, what should a LinkedList look like from the outside? Is a LinkedList really a chain of Node objects? Or is that just an implementation detail? And if it is just an implementation detail, how will the LinkedList let users access each of the elements in the LinkedList one at a time?

The key insight is the realization that a LinkedList is not a chain of Node s. That may be how it is built, but that is not what it is. What it is is a sequence of elements. Therefore the LinkedList abstraction should provide a LinkedListIterator class as well, and that LinkedListIterator might have an operator++ to go to the next element, and it might have a get() / set() pair to access its value stored in the Node (the value in the Node element is solely the responsibility of the LinkedList user, which is why there is a get() / set() pair that allows the user to freely manipulate that value).

Starting from the user’s perspective, we might want our LinkedList class to support operations that look similar to accessing an array using pointer arithmetic:

To implement this interface, LinkedList will need a begin() method and an end() method. These return a LinkedListIterator object. The LinkedListIterator will need a method to go forward, ++p ; a method to access the current element, *p ; and a comparison operator, p != a.end() .

The code follows. The important thing to notice is that LinkedList does not have any methods that let users access Node s. Node s are an implementation technique that is completely buried. This makes the LinkedList class safer (no chance a user will mess up the invariants and linkages between the various nodes), easier to use (users don’t need to expend extra effort keeping the node-count equal to the actual number of nodes, or any other infrastructure stuff), and more flexible (by changing a single typedef , users could change their code from using LinkedList to some other list-like class and the bulk of their code would compile cleanly and hopefully with improved performance characteristics).

Here are the methods that are obviously inlinable (probably in the same header file):

Conclusion: The linked list had two different kinds of data. The values of the elements stored in the linked list are the responsibility of the user of the linked list (and only the user; the linked list itself makes no attempt to prohibit users from changing the third element to 5), and the linked list’s infrastructure data ( next pointers, etc.), whose values are the responsibility of the linked list (and only the linked list; e.g., the linked list does not let users change (or even look at!) the various next pointers).

Thus the only get() / set() methods were to get and set the elements of the linked list, but not the infrastructure of the linked list. Since the linked list hides the infrastructure pointers/etc., it is able to make very strong promises regarding that infrastructure (e.g., if it were a doubly linked list, it might guarantee that every forward pointer was matched by a backwards pointer from the next Node ).

So, we see here an example of where the values of some of a class’s data is the responsibility of users (in which case the class needs to have get() / set() methods for that data) but the data that the class wants to control does not necessarily have get() / set() methods.

Note: the purpose of this example is not to show you how to write a linked-list class. In fact you should not “roll your own” linked-list class since you should use one of the “container classes” provided with your compiler. Ideally you’ll use one of the standard container classes such as the std::list<T> template.

How can I overload the prefix and postfix forms of operators ++ and -- ?

Via a dummy parameter.

Since the prefix and postfix ++ operators can have two definitions, the C++ language gives us two different signatures. Both are called operator++() , but the prefix version takes no parameters and the postfix version takes a dummy int . (Although this discussion revolves around the ++ operator, the -- operator is completely symmetric, and all the rules and guidelines that apply to one also apply to the other.)

Note the different return types: the prefix version returns by reference, the postfix version by value. If that’s not immediately obvious to you, it should be after you see the definitions (and after you remember that y = x++ and y = ++x set y to different things).

The other option for the postfix version is to return nothing:

However you must not make the postfix version return the this object by reference; you have been warned.

Here’s how you use these operators:

Assuming the return types are not ‘void’, you can use them in larger expressions:

Which is more efficient: i++ or ++i ?

++i is sometimes faster than, and is never slower than, i++ .

For intrinsic types like int , it doesn’t matter: ++i and i++ are the same speed. For class types like iterators or the previous FAQ’s Number class, ++i very well might be faster than i++ since the latter might make a copy of the this object.

The overhead of i++ , if it is there at all, won’t probably make any practical difference unless your app is CPU bound. For example, if your app spends most of its time waiting for someone to click a mouse, doing disk I/O, network I/O, or database queries, then it won’t hurt your performance to waste a few CPU cycles. However it’s just as easy to type ++i as i++ , so why not use the former unless you actually need the old value of i .

So if you’re writing i++ as a statement rather than as part of a larger expression, why not just write ++i instead? You never lose anything, and you sometimes gain something. Old line C programmers are used to writing i++ instead of ++i . E.g., they’ll say, for (i = 0; i < 10; i++) ... . Since this uses i++ as a statement, not as a part of a larger expression, then you might want to use ++i instead. For symmetry, I personally advocate that style even when it doesn’t improve speed, e.g., for intrinsic types and for class types with postfix operators that return void .

Obviously when i++ appears as a part of a larger expression, that’s different: it’s being used because it’s the only logically correct solution, not because it’s an old habit you picked up while programming in C.

Please Login to submit a recommendation.

If you don’t have an account, you can register for free.

cppreference.com

Overload resolution.

(C++20)
(C++20)
(C++11)
(C++20)
(C++17)
(C++11)
(C++11)
General topics
(C++11)
-
-expression
block


/
(C++11)
(C++11)
(C++11)
(C++20)
(C++20)
(C++11)

expression
pointer
specifier

specifier (C++11)
specifier (C++11)
(C++11)

(C++11)
(C++11)
(C++11)
Declarations
specifier
(C++11)
(C++20)
Function calls
Overloading

In order to compile a function call, the compiler must first perform name lookup , which, for functions, may involve argument-dependent lookup , and for function templates may be followed by template argument deduction .

If the name refers to more than one entity, it is said to be overloaded , and the compiler must determine which overload to call. In simple terms, the overload whose parameters match the arguments most closely is the one that is called.

In detail, overload resolution proceeds through the following steps:

  • Building the set of candidate functions .
  • Trimming the set to only viable functions .
  • Analyzing the set to determine the single best viable function (this may involve ranking of implicit conversion sequences ).

Besides function calls, overloaded function names may appear in several additional contexts, where different rules apply: see Address of an overloaded function .

If a function cannot be selected by overload resolution, it cannot be used (e.g. it is a templated entity with a failed constraint ).

Candidate functions Call to a named function Call to a class object Call to an overloaded operator Initialization by constructor Copy-initialization by conversion Non-class initialization by conversion Reference initialization by conversion List-initialization Additional rules for function template candidates Additional rules for constructor candidates Additional rules for member function candidates Viable functions Best viable function Ranking of implicit conversion sequences Implicit conversion sequence in list-initialization Defect reports References See also

[ edit ] Candidate functions

Before overload resolution begins, the functions selected by name lookup and template argument deduction are combined to form the set of candidate functions . The exact details depend on the context in which overload resolution will take place.

[ edit ] Call to a named function

If E in a function call expression E ( args ) names a set of overloaded functions and/or function templates (but not callable objects), the following rules are followed:

  • If the expression E has the form PA - > B or A. B (where A has class type cv T ), then B is looked up as a member function of T . The function declarations found by that lookup are the candidate functions. The argument list for the purpose of overload resolution has the implied object argument of type cv T .
  • If the expression E is a primary expression , the name is looked up following normal rules for function calls (which may involve ADL ). The function declarations found by this lookup are (due to the way lookup works) either:
  • all non-member functions (in which case the argument list for the purpose of overload resolution is exactly the argument list used in the function call expression)
  • all member functions of some class T , in which case, if this is in scope and is a pointer to T or to a derived class of T , * this is used as the implied object argument. Otherwise (if this is not in scope or does not point to T ), a fake object of type T is used as the implied object argument, and if overload resolution subsequently selects a non-static member function, the program is ill-formed.

[ edit ] Call to a class object

If E in a function call expression E ( args ) has class type cv T , then

  • The function-call operators of T are obtained by ordinary lookup of the name operator ( ) in the context of the expression ( E ) . operator ( ) , and every declaration found is added to the set of candidate functions.
  • For each non- explicit user-defined conversion function in T or in a base of T (unless hidden), whose cv-qualifiers are the same or greater than T 's cv-qualifiers, and where the conversion function converts to:
  • pointer-to-function
  • reference-to-pointer-to-function
  • reference-to-function

In any case, the argument list for the purpose of overload resolution is the argument list of the function call expression preceded by the implied object argument E (when matching against the surrogate function, the user-defined conversion will automatically convert the implied object argument to the first argument of the surrogate function).

[ edit ] Call to an overloaded operator

If at least one of the arguments to an operator in an expression has a class type or an enumeration type, both builtin operators and user-defined operator overloads participate in overload resolution, with the set of candidate functions selected as follows:

For a unary operator @ whose argument has type T1 (after removing cv-qualifications), or binary operator @ whose left operand has type T1 and right operand of type T2 (after removing cv-qualifications), the following sets of candidate functions are prepared:

: y, x <= y, x > y, and x >= y, all member, non-member, and built-in operator<=>s found are added to the set. y, x <= y, x > y, and x >= y as well as the three-way comparison expression x <=> y, a synthesized candidate with the order of the two parameters reversed is added for each member, non-member, and built-in operator<=>s found. = y, all member, non-member, and built-in operator==s found are added to the set, unless there is a matching operator!=. y and x != y, a synthesized candidate with the order of the two parameters reversed is added for each member, non-member, and built-in operator==s found, unless there is a matching operator!=. In all cases, rewritten candidates are not considered in the context of the rewritten expression. For all other operators, the rewritten candidate set is empty. (since C++20)

The set of candidate functions to be submitted for overload resolution is a union of the sets above. The argument list for the purpose of overload resolution consists of the operands of the operator except for operator-> , where the second operand is not an argument for the function call (see member access operator ).

If the overload resolution selects a built-in candidate, the user-defined conversion sequence from an operand of class type is not allowed to have a second standard conversion sequence: the user-defined conversion function must give the expected operand type directly:

For operator, , the unary operator & , and operator - > , if there are no viable functions (see below) in the set of candidate functions, then the operator is reinterpreted as a built-in.

If a rewritten operator<=> candidate is selected by overload resolution for an operator , x @ y is interpreted as the rewritten expression: 0 @ (y <=> x) if the selected candidate is a synthesized candidate with reversed order of parameters, or (x <=> y) @ 0 otherwise, using the selected rewritten operator<=> candidate.

If a rewritten operator== candidate is selected by overload resolution for an operator (which is either or ), its return type must be (possibly cv-qualified) bool, and x @ y is interpreted as the rewritten expression: y == x or !(y == x) if the selected candidate is a synthesized candidate with reversed order of parameters, or !(x == y) otherwise, using the selected rewritten operator== candidate.

Overload resolution in this case has a final tiebreaker preferring non-rewritten candidates to rewritten candidates, and preferring non-synthesized rewritten candidates to synthesized rewritten candidates.

This lookup with the reversed arguments order makes it possible to write just operator<=>( , const char*) and operator==( , const char*) to generate all comparisons between and const char*, both ways. See for more detail.

(since C++20)

[ edit ] Initialization by constructor

When an object of class type is direct-initialized or default-initialized (including default-initialization in the context of copy-list-initialization ) (since C++11) , the candidate functions are all constructors of the class being initialized. The argument list is the expression list of the initializer.

Otherwise, the candidate functions are all converting constructors of the class being initialized. The argument list is the expression of the initializer.

For default-initialization in the context of copy-list-initialization, if an constructor is chosen, the initialization is ill-formed.

(since C++11)

[ edit ] Copy-initialization by conversion

If copy-initialization of an object of class type requires that a user-defined conversion is called to convert the initializer expression of type cv S to the type cv T of the object being initialized, the following functions are candidate functions:

  • all converting constructors of T
  • the non- explicit conversion functions from S and its base classes (unless hidden) to T or class derived from T or a reference to such. If this copy-initialization is part of the direct-initialization sequence of cv T (initializing a reference to be bound to the first parameter of a constructor that takes a reference to cv T ), then explicit conversion functions are also considered.

Either way, the argument list for the purpose of overload resolution consists of a single argument which is the initializer expression, which will be compared against the first argument of the constructor or against the implicit object argument of the conversion function.

[ edit ] Non-class initialization by conversion

When initialization of an object of non-class type cv1 T requires a user-defined conversion function to convert from an initializer expression of class type cv S , the following functions are candidates:

  • the non-explicit user-defined conversion functions of S and its base classes (unless hidden) that produce type T or a type convertible to T by a standard conversion sequence , or a reference to such type. cv-qualifiers on the returned type are ignored for the purpose of selecting candidate functions.
  • if this is direct-initialization , the explicit user-defined conversion functions of S and its base classes (unless hidden) that produce type T or a type convertible to T by a qualification conversion , or a reference to such type, are also considered.

Either way, the argument list for the purpose of overload resolution consists of a single argument which is the initializer expression, which will be compared against the implicit object argument of the conversion function.

[ edit ] Reference initialization by conversion

During reference initialization , where the reference to cv1 T is bound to the lvalue or rvalue result of a conversion from the initializer expression from the class type cv2 S , the following functions are selected for the candidate set:

  • The non-explicit user-defined conversion functions of S and its base classes (unless hidden) to the type
  • (when initializing lvalue reference or rvalue reference to function) lvalue reference to cv2 T2
  • (when initializing rvalue reference or lvalue reference to function) cv2 T2 or rvalue reference to cv2 T2
  • For direct initialization, the explicit user-defined conversion functions are also considered if T2 is the same type as T or can be converted to type T with a qualification conversion.

[ edit ] List-initialization

When an object of non-aggregate class type T is list-initialized , two-phase overload resolution takes place.

  • at phase 1, the candidate functions are all initializer-list constructors of T and the argument list for the purpose of overload resolution consists of a single initializer list argument
  • if overload resolution fails at phase 1, phase 2 is entered, where the candidate functions are all constructors of T and the argument list for the purpose of overload resolution consists of the individual elements of the initializer list.

If the initializer list is empty and T has a default constructor, phase 1 is skipped.

In copy-list-initialization, if phase 2 selects an explicit constructor, the initialization is ill-formed (as opposed to all over copy-initializations where explicit constructors are not even considered).

[ edit ] Additional rules for function template candidates

If name lookup found a function template, template argument deduction and checking of any explicit template arguments are performed to find the template argument values (if any) that can be used in this case:

  • If both succeeds, the template arguments are used to synthesize declarations of the corresponding function template specializations, which are added to the candidate set, and such specializations are treated just like non-template functions except where specified otherwise in the tie-breaker rules below.
  • If argument deduction fails or the synthesized function template specialization would be ill-formed, no such function is added to the candidate set (see SFINAE ).

If a name refers to one or more function templates and also to a set of overloaded non-template functions, those functions and the specializations generated from the templates are all candidates.

See function template overloading for further detail.

If a constructor template or conversion function template has a which happens to be , after deduction, if the context requires a candidate that is not explicit and the generated specialization is explicit, it is removed from the candidate set.

(since C++20)

[ edit ] Additional rules for constructor candidates

Defaulted and that are defined as deleted are excluded in the set of candidate functions.

A constructor from class type that has a first parameter of type “reference to ” (including such a constructor instantiated from a template) is excluded from the set of candidate functions when constructing an object of type if all following conditions are satisfied:

is to . is reference-related to .
(since C++11)

[ edit ] Additional rules for member function candidates

If any candidate function is a member function (static or non-static) that does not have an explicit object parameter (since C++23) , but not a constructor, it is treated as if it has an extra parameter ( implicit object parameter ) which represents the object for which they are called and appears before the first of the actual parameters.

Similarly, the object on which a member function is being called is prepended to the argument list as the implied object argument .

For member functions of class X , the type of the implicit object parameter is affected by cv-qualifications and ref-qualifications of the member function as described in member functions .

The user-defined conversion functions are considered to be members of the implied object argument for the purpose of determining the type of the implicit object parameter .

The member functions introduced by a using-declaration into a derived class are considered to be members of the derived class for the purpose of defining the type of the implicit object parameter .

For the static member functions, the is considered to match any object: its type is not examined and no conversion sequence is attempted for it.

(until C++23)

For the rest of overload resolution, the implied object argument is indistinguishable from other arguments, but the following special rules apply to the implicit object parameter :

[ edit ] Viable functions

Given the set of candidate functions, constructed as described above, the next step of overload resolution is examining arguments and parameters to reduce the set to the set of viable functions

To be included in the set of viable functions, the candidate function must satisfy the following:

If the function has an associated , it must be satisfied (since C++20)

User-defined conversions (both converting constructors and user-defined conversion functions) are prohibited from taking part in implicit conversion sequence where it would make it possible to apply more than one user-defined conversion. Specifically, they are not considered if the target of the conversion is the first parameter of a constructor or the implicit object parameter of a user-defined conversion function, and that constructor/user-defined conversion is a candidate for

  • copy-initialization of a class by user-defined conversion ,
  • initialization of a non-class type by a conversion function ,
  • initialization by conversion function for direct reference binding ,
  • initialization by constructor during the second (direct-initialization) step of class copy-initialization ,
, and the conversion is to or reference to (possibly cv-qualified) : A { A(int); }; struct B { B(A); };   B b{{0}}; // list-initialization of B   // candidates: B(const B&), B(B&&), B(A) // {0} -> B&& not viable: would have to call B(A) // {0} -> const B&: not viable: would have to bind to rvalue, would have to call B(A) // {0} -> A viable. Calls A(int): user-defined conversion to A is not banned (since C++11)

[ edit ] Best viable function

For each pair of viable function F1 and F2 , the implicit conversion sequences from the i -th argument to i -th parameter are ranked to determine which one is better (except the first argument, the implicit object argument for static member functions has no effect on the ranking)

F1 is determined to be a better function than F2 if implicit conversions for all arguments of F1 are not worse than the implicit conversions for all arguments of F2, and

(only in context of initialization by conversion function for direct reference binding of a reference to function type), the result of is the same kind of reference (lvalue or rvalue) as the reference being initialized, and the result of is not, or, if not that, (since C++11)
and are non-template functions satisfying all following conditions: (since C++23). is more constrained than according to the . <typename T = int> struct S { constexpr void f(); // #1 constexpr void f(this S&) requires true; // #2 };   void test() { S<> s; s.f(); // calls #2 } , or, if not that, (since C++20)
is a constructor for a class D, is a constructor for a base class B of D, and for all arguments the corresponding parameters of and have the same type: A { A(int = 0); };   struct B: A { using A::A;   B(); };   B b; // OK, B::B() , or, if not that, (since C++11)
is a rewritten candidate and is not, or, if not that, and are both rewritten candidates, and is a synthesized rewritten candidate with reversed order of parameters and is not, or, if not that, (since C++20)
is generated from a and is not, or, if not that, is the and is not, or, if not that, is generated from a non-template constructor and is generated from a constructor template: <class T> struct A { using value_type = T; A(value_type); // #1 A(const A&); // #2 A(T, T, int); // #3   template<class U> A(int, T, U); // #4 }; // #5 is A(A), the copy deduction candidate   A x(1, 2, 3); // uses #3, generated from a non-template constructor   template<class T> A(T) -> A<T>; // #6, less specialized than #5   A a (42); // uses #6 to deduce A<int> and #1 to initialize A b = a; // uses #5 to deduce A<int> and #2 to initialize   template<class T> A(A<T>) -> A<A<T>>; // #7, as specialized as #5 A b2 = a; // uses #7 to deduce A<A<int>> and #1 to initialize (since C++17)

These pair-wise comparisons are applied to all viable functions. If exactly one viable function is better than all others, overload resolution succeeds and this function is called. Otherwise, compilation fails.

If the best viable function resolves to a function for which multiple declarations were found, and if any two of these declarations inhabit different scopes and specify a default argument that made the function viable, the program is ill-formed.

[ edit ] Ranking of implicit conversion sequences

The argument-parameter implicit conversion sequences considered by overload resolution correspond to implicit conversions used in copy initialization (for non-reference parameters), except that when considering conversion to the implicit object parameter or to the left-hand side of assignment operator, conversions that create temporary objects are not considered. When the parameter is the implicit object parameter of a static member function, the implicit conversion sequence is a standard conversion sequence that is neither better nor worse than any other standard conversion sequence. (since C++23)

Each type of standard conversion sequence is assigned one of three ranks:

The rank of the standard conversion sequence is the worst of the ranks of the standard conversions it holds (there may be up to three conversions )

Binding of a reference parameter directly to the argument expression is either identity or a derived-to-base conversion:

Since ranking of conversion sequences operates with types and value categories only, a bit field can bind to a reference argument for the purpose of ranking, but if that function gets selected, it will be ill-formed.

the cv-qualification of the result of is a proper subset of the cv-qualification of the result of , and is not the (until C++11).

(until C++20)

the result of can be converted to the result of by a qualification conversion.

(since C++20)
A list-initialization sequence is than list-initialization sequence if the corresponding parameters are references to arrays, and L1 converts to type "array of N1 T," L2 converts to type "array of N2 T", and N1 is smaller than N2. (since C++11)
(until C++20)
A list-initialization sequence is than list-initialization sequence if the corresponding parameters are references to arrays, and L1 and L2 convert to arrays of same element type, and either f(int (&&)[] ); // overload #1 void f(double (&&)[] ); // overload #2 void f(int (&&)[2]); // overload #3   f({1}); // #1: Better than #2 due to conversion, better than #3 due to bounds f({1.0}); // #2: double -> double is better than double -> int f({1.0, 2.0}); // #2: double -> double is better than double -> int f({1, 2}); // #3: -> int[2] is better than -> int[], // and int -> int is better than int -> double (since C++20)

If two conversion sequences are indistinguishable because they have the same rank, the following additional rules apply:

Conversion that promotes an whose underlying type is fixed to its underlying type is better than one that promotes to the promoted underlying type, if the two types are different. num : char { one = '0' }; << num::one; // '0', not 48 (since C++11)
A conversion in either direction between floating-point type and floating-point type is better than a conversion in the same direction between and arithmetic type if of is equal to the rank of , and is not a floating-point type, or is a floating-point type whose rank is not equal to the rank of , or of is greater than the subrank of . f( ); int f( ); int f(long long);   float x; y;   int i = f(x); // calls f(std::float32_t) on implementations where // float and std::float32_t have equal conversion ranks int j = f(y); // error: ambiguous, no equal conversion rank (since C++23)

Ambiguous conversion sequences are ranked as user-defined conversion sequences because multiple conversion sequences for an argument can exist only if they involve different user-defined conversions:

[ edit ] Implicit conversion sequence in list-initialization

In list initialization , the argument is a braced-init-list , which isn't an expression, so the implicit conversion sequence into the parameter type for the purpose of overload resolution is decided by the following special rules:

  • If the parameter type is some aggregate X and the initializer list consists of exactly one element of same or derived class (possibly cv-qualified), the implicit conversion sequence is the one required to convert the element to the parameter type.
  • Otherwise, if the parameter type is a reference to character array and the initializer list has a single element that is an appropriately-typed string literal, the implicit conversion sequence is the identity conversion.
  • Otherwise, if the parameter type is std:: initializer_list < X > , and there is a non-narrowing implicit conversion from every element of the initializer list to X , the implicit conversion sequence for the purpose of overload resolution is the worst conversion necessary. If the braced-init-list is empty, the conversion sequence is the identity conversion.
  • Otherwise, if the parameter type is "array of N T" (this only happens for references to arrays), the initializer list must have N or less elements, and the worst implicit conversion necessary to convert every element of the list (or the empty pair of braces {} if the list is shorter than N) to T is the one used.
is the one used. (since C++20)
  • Otherwise, if the parameter type is a non-aggregate class type X , overload resolution picks the constructor C of X to initialize from the argument initializer list
  • If C is not an initializer-list constructor and the initializer list has a single element of possibly cv-qualified X, the implicit conversion sequence has Exact Match rank. If the initializer list has a single element of possibly cv-qualified type derived from X, the implicit conversion sequence has Conversion rank. (note the difference from aggregates: aggregates initialize directly from single-element init lists before considering aggregate initialization , non-aggregates consider initializer_list constructors before any other constructors)
  • otherwise, the implicit conversion sequence is a user-defined conversion sequence with the second standard conversion sequence an identity conversion.

If multiple constructors are viable but none is better than the others, the implicit conversion sequence is the ambiguous conversion sequence.

  • Otherwise, if the parameter type is an aggregate which can be initialized from the initializer list according by aggregate initialization , the implicit conversion sequence is a user-defined conversion sequence with the second standard conversion sequence an identity conversion.
  • Otherwise, if the parameter is a reference, reference initialization rules apply
  • Otherwise, if the parameter type is not a class and the initializer list has one element, the implicit conversion sequence is the one required to convert the element to the parameter type
  • Otherwise, if the parameter type is not a class type and if the initializer list has no elements, the implicit conversion sequence is the identity conversion.

If the argument is a designated initializer list and the parameter is not a reference, a conversion is only possible if the parameter has an aggregate type that can be initialized from that initializer list according to the rules for , in which case the implicit conversion sequence is a user-defined conversion sequence whose second standard conversion sequence is an identity conversion.

If, after overload resolution, the order of declaration of the aggregate's members does not match for the selected overload, the initialization of the parameter will be ill-formed.

A { int x, y; }; struct B { int y, x; };   void f(A a, int); // #1 void f(B b, ...); // #2 void g(A a); // #3 void g(B b); // #4   void h() { f({.x = 1, .y = 2}, 0); // OK; calls #1 f({.y = 2, .x = 1}, 0); // error: selects #1, initialization of a fails // due to non-matching member order g({.x = 1, .y = 2}); // error: ambiguous between #3 and #4 }


(since C++20)

[ edit ] Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
C++98 the behavior was unspecified when the same
function with possibly different default
arguments (from different scopes) is selected
the program is ill-
formed in this case
C++98 the conversion sequence from a string literal
to char* was better than that to const char*
even though the former is deprecated
the rank of the deprecated
conversion is lowered (it
was removed in C++11)
C++98 it was invalid if the overload set named by contains
a non-static member function in the case of
only invalid if overload
resolution selects a non-static
member function in this case
C++98 references and pointers were handled insonsistently in
overloading resolution with user defined conversions
they are handled
consistently
C++98 surrogate call functions were not added to
the set of candidate functions for conversion
functions declared in inaccessible base classes
removed the accessibility
constraint, the program is
ill-formed if a surrogate call
function is selected and the
corresponding conversion
function cannot be called
C++98 when a function template is selected as a
candidate, its specializations were instantiated
using template argument deduction
no instantiation will occur
in this case, their declarations
will be synthesized
C++98 when the implicit conversions for arguments are equally
good, a non-template conversion function was always
better than a conversion function template, even if the
latter may have a better standard conversion sequence
standard conversion
sequences are compared
before specialization levels
C++11 overload resolution based on size of arrays was not specified a shorter array is
better when possible
C++11 the determination of the candidate functions when
binding a reference to a conversion result was not clear
made clear
C++98 qualification conversion was checked before reference
binding when comparing standard conversion sequences
reversed
C++11 a non-explicit user-defined conversion function declared with
a ref-qualifier did not have a corresponding surrogate function
it has a corresponding
surrogate function
C++11 same-type list-initialization of
aggregates and arrays was omitted
initialization defined
C++11 conversion from enum to its underlying type
did not prefer the fixed underlying type
fixed type is preferred
to what it promotes to
C++98 the set of member candidates of a unary operator
whose argument has type was empty if
is a class currently being defined
the set is the result of
qualified name lookup of
in this case
C++98 when a built-in candidate is selected by overload resolution,
the operands would undergo conversion without restriction
only convert class type operands,
and disabled the second
standard conversion sequence
C++98 ill-formed synthesized function template specializations could
be added to the candidate set, making the program ill-formed
they are not added
to the candidate set
C++11 user-defined conversion is applied to the single initializer
in a nested initializer list during list-initialization
due to the resolution of
not applied
C++11 initializer list constructors lost to copy
constructors when list-initializing from {X}
non-aggregates consider
initializer lists first
C++11 there was no tiebreaker between
inherited and non-inherited constructors
non-inherited constructor wins
C++20 built-in candidates with the same parameter
list as a rewritten non-member candidate
were added to the list of built-in candidates
not added
C++98 when a built-in assignment operator is considered,
the first parameter could not bound to a
temporary, which is already impossible
removed the
redundant requirement
C++20 the conversion restriction regarding designated initializer
lists was applied even if the parameter is a reference
not restricted in this case
C++23 the explicit object paramaeter was included
when comparing parameter-type-lists
excluded
C++11 the overload resolution for default-initialization in the context
of copy-list-initialization only considered converting constructor
considers all constructors
C++20 rewritten candidates based on operator== are added
for a != b even if a matching operator!= exists
not added
  • ↑ The type of the of the first parameter of a built-in assignment operator is “lvalue reference to possibly volatile-qualified T ”. References of this type cannot bould to a temporary.

[ edit ] References

  • C++23 standard (ISO/IEC 14882:2024):
  • 12.2 Overload resolution [over.match]
  • C++20 standard (ISO/IEC 14882:2020):
  • 12.4 Overload resolution [over.match]
  • C++17 standard (ISO/IEC 14882:2017):
  • 16.3 Overload resolution [over.match]
  • C++14 standard (ISO/IEC 14882:2014):
  • 13.3 Overload resolution [over.match]
  • C++11 standard (ISO/IEC 14882:2011):
  • C++03 standard (ISO/IEC 14882:2003):

[ edit ] See also

  • Name lookup
  • Argument-dependent lookup
  • Template argument deduction
  • Recent changes
  • Offline version
  • What links here
  • Related changes
  • Upload file
  • Special pages
  • Printable version
  • Permanent link
  • Page information
  • In other languages
  • This page was last modified on 24 July 2024, at 01:59.
  • Privacy policy
  • About cppreference.com
  • Disclaimers

Powered by MediaWiki

operator overloading

(C++20)
(C++20)
(C++11)
(C++11)
(C++11)
(C++17)
General topics
(C++11)
-
-expression
- block
(C++11)
(C++11)
(C++11)
/
(C++11)
(C++11)
Expressions
expression
pointer
specifier
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
General
(lvalue, rvalue, xvalue)
(sequence points)
(C++11)
Literals
including
(C++11)
(C++11)
Operators
: , , , , , , , , , ,
: , , ,
: , , , , , , , , , , , ,
: , ,
: , , , , , , (C++20)
: , , , , , ,
: , ,
(C++20)
(C++17)
(C++11)
(C++11)
Conversions
,

Customizes the C++ operators for operands of user-defined types.

Overloaded operators are functions with special function names:

op (1)
type (2)

(3)

(4)
suffix-identifier (5) (since C++11)
op - any of the following 38 (until C++20)40 (since C++20) operators:+ - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= << >> >>= <<= == != <= >= <=> (since C++20) && || ++ -- , ->* -> ( ) [ ] co_await (since C++20)

Overloaded operators

When an operator appears in an expression , and at least one of its operands has a class type or an enumeration type , then overload resolution is used to determine the user-defined function to be called among all the functions whose signatures match the following:

Expression As member function As non-member function Example
@a (a).operator@ ( ) operator@ (a) ! calls .operator!()
a@b (a).operator@ (b) operator@ (a, b) << 42 calls .operator<<(42)
a=b (a).operator= (b) cannot be non-member s; s = "abc"; calls s.operator=("abc")
a(b...) (a).operator()(b...) cannot be non-member r; auto n = r(); calls r.operator()()
a[b] (a).operator[](b) cannot be non-member <int, int> m; m[1] = 2; calls m.operator[](1)
a-> (a).operator-> ( ) cannot be non-member auto p = <S>(); p->bar() calls p.operator->()
a@ (a).operator@ (0) operator@ (a, 0) <int>::iterator i = v.begin(); i++ calls i.operator++(0)

in this table, is a placeholder representing all matching operators: all prefix operators in @a, all postfix operators other than -> in a@, all infix operators other than = in a@b

Note: for overloading user-defined conversion functions , user-defined literals , allocation and deallocation see their respective articles.

Overloaded operators (but not the built-in operators) can be called using function notation:

Restrictions

  • The operators :: (scope resolution), . (member access), .* (member access through pointer to member), and ?: (ternary conditional) cannot be overloaded.
  • New operators such as ** , <> , or &| cannot be created.
  • The overloads of operators && and || lose short-circuit evaluation.
  • The overload of operator -> must either return a raw pointer, or return an object (by reference or by value) for which operator -> is in turn overloaded.
  • It is not possible to change the precedence, grouping, or number of operands of operators.
, , and (comma) lose their special when overloaded and behave like regular function calls even when they are used without function-call notation. (until C++17)

Canonical implementations

Other than the restrictions above, the language puts no other constraints on what the overloaded operators do, or on the return type (it does not participate in overload resolution), but in general, overloaded operators are expected to behave as similar as possible to the built-in operators: operator + is expected to add, rather than multiply its arguments, operator = is expected to assign, etc. The related operators are expected to behave similarly ( operator + and operator + = do the same addition-like operation). The return types are limited by the expressions in which the operator is expected to be used: for example, assignment operators return by reference to make it possible to write a = b = c = d , because the built-in operators allow that.

Commonly overloaded operators have the following typical, canonical forms: [1]

Assignment operator

The assignment operator ( operator = ) has special properties: see copy assignment and move assignment for details.

The canonical copy-assignment operator is expected to perform no action on self-assignment , and to return the lhs by reference:

The canonical move assignment is expected to leave the moved-from object in valid state (that is, a state with class invariants intact), and either do nothing or at least leave the object in a valid state on self-assignment, and return the lhs by reference to non-const, and be noexcept:

In those situations where copy assignment cannot benefit from resource reuse (it does not manage a heap-allocated array and does not have a (possibly transitive) member that does, such as a member std::vector or std::string ), there is a popular convenient shorthand: the copy-and-swap assignment operator, which takes its parameter by value (thus working as both copy- and move-assignment depending on the value category of the argument), swaps with the parameter, and lets the destructor clean it up.

This form automatically provides strong exception guarantee , but prohibits resource reuse.

Stream extraction and insertion

The overloads of operator>> and operator<< that take a std:: istream & or std:: ostream & as the left hand argument are known as insertion and extraction operators. Since they take the user-defined type as the right argument ( b in a@b ), they must be implemented as non-members.

These operators are sometimes implemented as friend functions .

Function call operator

When a user-defined class overloads the function call operator, operator ( ) , it becomes a FunctionObject type. Many standard algorithms, from std:: sort to std:: accumulate accept objects of such types to customize behavior. There are no particularly notable canonical forms of operator ( ) , but to illustrate the usage

Increment and decrement

When the postfix increment and decrement appear in an expression, the corresponding user-defined function ( operator ++ or operator -- ) is called with an integer argument 0 . Typically, it is implemented as T operator ++ ( int ) , where the argument is ignored. The postfix increment and decrement operator is usually implemented in terms of the prefix version:

Although canonical form of pre-increment/pre-decrement returns a reference, as with any operator overload, the return type is user-defined; for example the overloads of these operators for std::atomic return by value.

Binary arithmetic operators

Binary operators are typically implemented as non-members to maintain symmetry (for example, when adding a complex number and an integer, if operator+ is a member function of the complex type, then only complex + integer would compile, and not integer + complex ). Since for every binary arithmetic operator there exists a corresponding compound assignment operator, canonical forms of binary operators are implemented in terms of their compound assignments:

Relational operators

Standard algorithms such as std:: sort and containers such as std:: set expect operator < to be defined, by default, for the user-provided types, and expect it to implement strict weak ordering (thus satisfying the Compare requirements). An idiomatic way to implement strict weak ordering for a structure is to use lexicographical comparison provided by std::tie :

Typically, once operator < is provided, the other relational operators are implemented in terms of operator < .

Likewise, the inequality operator is typically implemented in terms of operator == :

When three-way comparison (such as std::memcmp or std::string::compare ) is provided, all six relational operators may be expressed through that:

All six relational operators are automatically generated by the compiler if the three-way comparison operator operator<=> is defined, and that operator, in turn, is generated by the compiler if it is defined as defaulted:

Record { name; unsigned int floor; double weight; auto operator<=>(const Record&) = default; }; // records can now be compared with ==, !=, <, <=, >, and >=

See for details.

(since C++20)

Array subscript operator

User-defined classes that provide array-like access that allows both reading and writing typically define two overloads for operator [ ] : const and non-const variants:

If the value type is known to be a built-in type, the const variant should return by value.

Where direct access to the elements of the container is not wanted or not possible or distinguishing between lvalue c [ i ] = v ; and rvalue v = c [ i ] ; usage, operator[] may return a proxy. see for example std::bitset::operator[] .

To provide multidimensional array access semantics, e.g. to implement a 3D array access a [ i ] [ j ] [ k ] = x ; , operator[] has to return a reference to a 2D plane, which has to have its own operator[] which returns a reference to a 1D row, which has to have operator[] which returns a reference to the element. To avoid this complexity, some libraries opt for overloading operator ( ) instead, so that 3D access expressions have the Fortran-like syntax a ( i, j, k ) = x ;

Bitwise arithmetic operators

User-defined classes and enumerations that implement the requirements of BitmaskType are required to overload the bitwise arithmetic operators operator & , operator | , operator ^ , operator~ , operator & = , operator | = , and operator ^ = , and may optionally overload the shift operators operator << operator >> , operator >>= , and operator <<= . The canonical implementations usually follow the pattern for binary arithmetic operators described above.

Boolean negation operator

The operator operator ! is commonly overloaded by the user-defined classes that are intended to be used in boolean contexts. Such classes also provide a user-defined conversion function explicit operator bool ( ) (see std::basic_ios for the standard library example), and the expected behavior of operator ! is to return the value opposite of operator bool .

Rarely overloaded operators

The following operators are rarely overloaded:

  • The address-of operator, operator & . If the unary & is applied to an lvalue of incomplete type and the complete type declares an overloaded operator & , the behavior is undefined (until C++11) it is unspecified whether the operator has the built-in meaning or the operator function is called (since C++11) . Because this operator may be overloaded, generic libraries use std::addressof to obtain addresses of objects of user-defined types. The best known example of a canonical overloaded operator& is the Microsoft class CComPtr . An example of its use in EDSL can be found in boost.spirit .
  • The boolean logic operators, operator && and operator || . Unlike the built-in versions, the overloads cannot implement short-circuit evaluation. Also unlike the built-in versions, they do not sequence their left operand before the right one. (until C++17) In the standard library, these operators are only overloaded for std::valarray .
  • The comma operator, operator, . Unlike the built-in version, the overloads do not sequence their left operand before the right one. (until C++17) Because this operator may be overloaded, generic libraries use expressions such as a, void ( ) ,b instead of a,b to sequence execution of expressions of user-defined types. The boost library uses operator, in boost.assign , boost.spirit , and other libraries. The database access library SOCI also overloads operator, .
  • The member access through pointer to member operator - > * . There are no specific downsides to overloading this operator, but it is rarely used in practice. It was suggested that it could be part of smart pointer interface , and in fact is used in that capacity by actors in boost.phoenix . It is more common in EDSLs such as cpp.react .

Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
C++11 taking address of incomplete type that overloads address-of was undefined behavior the behavior is only unspecified
  • Operator precedence
  • Alternative operator syntax
Common operators

a = b
a += b
a -= b
a *= b
a /= b
a %= b
a &= b
a |= b
a ^= b
a <<= b
a >>= b

++a
--a
a++
a--

+a
-a
a + b
a - b
a * b
a / b
a % b
~a
a & b
a | b
a ^ b
a << b
a >> b

!a
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b
a <=> b

a[b]
*a
&a
a->b
a.b
a->*b
a.*b

a(...)
a, b
? :

Special operators

converts one type to another related type
converts within inheritance hierarchies
adds or removes qualifiers
converts type to unrelated type
converts one type to another by a mix of , , and
creates objects with dynamic storage duration
destructs objects previously created by the new expression and releases obtained memory area
queries the size of a type
queries the size of a (since C++11)
queries the type information of a type
checks if an expression can throw an exception (since C++11)
queries alignment requirements of a type (since C++11)

  • ↑ Operator Overloading on StackOverflow C++ FAQ

21.9 — Overloading the subscript operator

  • C++ Classes and Objects
  • C++ Polymorphism
  • C++ Inheritance
  • C++ Abstraction
  • C++ Encapsulation
  • C++ OOPs Interview Questions
  • C++ OOPs MCQ
  • C++ Interview Questions
  • C++ Function Overloading
  • C++ Programs
  • C++ Preprocessor
  • C++ Templates

Operator Overloading in C++

in C++, Operator overloading is a compile-time polymorphism. It is an idea of giving special meaning to an existing operator in C++ without changing its original meaning.

In this article, we will further discuss about operator overloading in C++ with examples and see which operators we can or cannot overload in C++.

C++ Operator Overloading

C++ has the ability to provide the operators with a special meaning for a data type, this ability is known as operator overloading. Operator overloading is a compile-time polymorphism. For example, we can overload an operator ‘+’ in a class like String so that we can concatenate two strings by just using +. Other example classes where arithmetic operators may be overloaded are Complex Numbers, Fractional Numbers, Big integers, etc.

int a; float b,sum; sum = a + b;

Here, variables “a” and “b” are of types “int” and “float”, which are built-in data types. Hence the addition operator ‘+’ can easily add the contents of “a” and “b”. This is because the addition operator “+” is predefined to add variables of built-in data type only. 

Implementation:

// C++ Program to Demonstrate the // working/Logic behind Operator // Overloading class A { statements ; }; int main () { A a1 , a2 , a3 ; a3 = a1 + a2 ; return 0 ; }

In this example, we have 3 variables “a1”, “a2” and “a3” of type “class A”. Here we are trying to add two objects “a1” and “a2”, which are of user-defined type i.e. of type “class A” using the “+” operator. This is not allowed, because the addition operator “+” is predefined to operate only on built-in data types. But here, “class A” is a user-defined type, so the compiler generates an error. This is where the concept of “Operator overloading” comes in.

Now, if the user wants to make the operator “+” add two class objects, the user has to redefine the meaning of the “+” operator such that it adds two class objects. This is done by using the concept of “Operator overloading”. So the main idea behind “Operator overloading” is to use C++ operators with class variables or class objects. Redefining the meaning of operators really does not change their original meaning; instead, they have been given additional meaning along with their existing ones.

Example of Operator Overloading in C++

// C++ Program to Demonstrate // Operator Overloading #include <iostream> using namespace std ; class Complex { private : int real , imag ; public : Complex ( int r = 0 , int i = 0 ) { real = r ; imag = i ; } // This is automatically called when '+' is used with // between two Complex objects Complex operator + ( Complex const & obj ) { Complex res ; res . real = real + obj . real ; res . imag = imag + obj . imag ; return res ; } void print () { cout << real << " + i" << imag << '\n' ; } }; int main () { Complex c1 ( 10 , 5 ), c2 ( 2 , 4 ); Complex c3 = c1 + c2 ; c3 . print (); }

Difference between Operator Functions and Normal Functions

Operator functions are the same as normal functions. The only differences are, that the name of an operator function is always the operator keyword followed by the symbol of the operator, and operator functions are called when the corresponding operator is used. 

#include <iostream> using namespace std ; class Complex { private : int real , imag ; public : Complex ( int r = 0 , int i = 0 ) { real = r ; imag = i ; } void print () { cout << real << " + i" << imag << endl ; } // The global operator function is made friend of this // class so that it can access private members friend Complex operator + ( Complex const & c1 , Complex const & c2 ); }; Complex operator + ( Complex const & c1 , Complex const & c2 ) { return Complex ( c1 . real + c2 . real , c1 . imag + c2 . imag ); } int main () { Complex c1 ( 10 , 5 ), c2 ( 2 , 4 ); Complex c3 = c1 + c2 ; // An example call to &quot;operator+&quot; c3 . print (); return 0 ; }

Can We Overload All Operators?  

Almost all operators can be overloaded except a few. Following is the list of operators that cannot be overloaded. 

sizeof typeid Scope resolution (::) Class member access operators (.(dot), .* (pointer to member operator)) Ternary or conditional (?:)

Operators that can be Overloaded in C++

We can overload

Unary operators Binary operators Special operators ( [ ], (), etc)

But, among them, there are some operators that cannot be overloaded. They are

Scope resolution operator [Tex](::)[/Tex] Member selection operator                              Member selection through  *

Pointer to a member variable

  • Conditional operator [Tex](?:)[/Tex]
  • Sizeof operator  sizeof()
Operators that can be overloadedExamples
Binary Arithmetic+, -, *, /, %
Unary Arithmetic +, -, ++, —
Assignment=, +=,*=, /=,-=, %=
Bitwise& , | , << , >> , ~ , ^
De-referencing(->)
Dynamic memory allocation,
De-allocation
New, delete 
Subscript[ ]
Function call ()
Logical &,  | |, !
Relational>, < , = =, <=, >=

Why can’t the above-stated operators be overloaded?

1. sizeof operator.

This returns the size of the object or datatype entered as the operand. This is evaluated by the compiler and cannot be evaluated during runtime. The proper incrementing of a pointer in an array of objects relies on the sizeof operator implicitly. Altering its meaning using overloading would cause a fundamental part of the language to collapse.

2. typeid Operator

This provides a CPP program with the ability to recover the actually derived type of the object referred to by a pointer or reference. For this operator, the whole point is to uniquely identify a type. If we want to make a user-defined type ‘look’ like another type, polymorphism can be used but the meaning of the typeid operator must remain unaltered, or else serious issues could arise.

3. Scope resolution (::) Operator

This helps identify and specify the context to which an identifier refers by specifying a namespace. It is completely evaluated at runtime and works on names rather than values. The operands of scope resolution are note expressions with data types and CPP has no syntax for capturing them if it were overloaded. So it is syntactically impossible to overload this operator.

4. Class member access operators (.(dot ), .* (pointer to member operator))

The importance and implicit use of class member access operators can be understood through the following example:

// C++ program to demonstrate operator overloading // using dot operator #include <iostream> using namespace std ; class ComplexNumber { private : int real ; int imaginary ; public : ComplexNumber ( int real , int imaginary ) { this -> real = real ; this -> imaginary = imaginary ; } void print () { cout << real << " + i" << imaginary ; } ComplexNumber operator + ( ComplexNumber c2 ) { ComplexNumber c3 ( 0 , 0 ); c3 . real = this -> real + c2 . real ; c3 . imaginary = this -> imaginary + c2 . imaginary ; return c3 ; } }; int main () { ComplexNumber c1 ( 3 , 5 ); ComplexNumber c2 ( 2 , 4 ); ComplexNumber c3 = c1 + c2 ; c3 . print (); return 0 ; }

Explanation:

The statement ComplexNumber c3 = c1 + c2; is internally translated as ComplexNumber c3 = c1.operator+ (c2); in order to invoke the operator function. The argument c1 is implicitly passed using the ‘.’ operator. The next statement also makes use of the dot operator to access the member function print and pass c3 as an argument. 

Besides, these operators also work on names and not values and there is no provision (syntactically) to overload them.

5. Ternary or conditional (?:) Operator

The ternary or conditional operator is a shorthand representation of an if-else statement. In the operator, the true/false expressions are only evaluated on the basis of the truth value of the conditional expression. 

conditional statement ? expression1 (if statement is TRUE) : expression2 (else)

A function overloading the ternary operator for a class say ABC using the definition

ABC operator ?: (bool condition, ABC trueExpr, ABC falseExpr);

would not be able to guarantee that only one of the expressions was evaluated. Thus, the ternary operator cannot be overloaded.

Important Points about Operator Overloading  

1) For operator overloading to work, at least one of the operands must be a user-defined class object.

2) Assignment Operator: Compiler automatically creates a default assignment operator with every class. The default assignment operator does assign all members of the right side to the left side and works fine in most cases (this behavior is the same as the copy constructor). See this for more details.

3) Conversion Operator: We can also write conversion operators that can be used to convert one type to another type. 

Example:  

// C++ Program to Demonstrate the working // of conversion operator #include <iostream> using namespace std ; class Fraction { private : int num , den ; public : Fraction ( int n , int d ) { num = n ; den = d ; } // Conversion operator: return float value of fraction operator float () const { return float ( num ) / float ( den ); } }; int main () { Fraction f ( 2 , 5 ); float val = f ; cout << val << '\n' ; return 0 ; }

Overloaded conversion operators must be a member method. Other operators can either be the member method or the global method.

4) Any constructor that can be called with a single argument works as a conversion constructor, which means it can also be used for implicit conversion to the class being constructed. 

// C++ program to demonstrate can also be used for implicit // conversion to the class being constructed #include <iostream> using namespace std ; class Point { private : int x , y ; public : Point ( int i = 0 , int j = 0 ) { x = i ; y = j ; } void print () { cout << "x = " << x << ", y = " << y << '\n' ; } }; int main () { Point t ( 20 , 20 ); t . print (); t = 30 ; // Member x of t becomes 30 t . print (); return 0 ; }

x = 20, y = 20 x = 30, y = 0

Quiz on Operator Overloading

Please Login to comment...

Similar reads.

  • cpp-operator-overloading
  • cpp-overloading
  • PS5 Pro Launched: Controller, Price, Specs & Features, How to Pre-Order, and More
  • How to Make Money on Twitch
  • How to activate Twitch on smart TV
  • 105 Funny Things to Do to Make Someone Laugh
  • #geekstreak2024 – 21 Days POTD Challenge Powered By Deutsche Bank

Improve your Coding Skills with Practice

 alt=

What kind of Experience do you want to share?

  • Stack Overflow for Teams Where developers & technologists share private knowledge with coworkers
  • Advertising & Talent Reach devs & technologists worldwide about your product, service or employer brand
  • OverflowAI GenAI features for Teams
  • OverflowAPI Train & fine-tune LLMs
  • Labs The future of collective knowledge sharing
  • About the company Visit the blog

Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Get early access and see previews of new features.

Assignment operator, using a dynamic array

I have a list of pointers to objects. What I want to do is read the list and store each object in a dynamic array of that object type. So I do this:

This appears to be what I want which means I need the assignment operator but I am a bit confused as to what to put in it and I am getting stack overflow errors, here is what I thought I needed to do:

this is a load of BS I no that but in my head this is what I want it to do but I don't fully understand how I implement it.

If anyone can help or suggest a better way to achieve what I need it would be appreciated.

The reason for doing this is the objects stored on this list are normally iterated through each frame and copied into a temporary object. But the list is not changed during the running of the program, which means I don't need to copy each frame, only once at the start. And I need a dynamic array because I don't know how many objects will be stored in the list.

  • operator-overloading
  • operator-keyword
  • dynamic-arrays

RobBain85's user avatar

  • Does your list contain pointers, or actual objects? (ie list<ClassA> or list<ClassA*> )? –  David Brown Commented Apr 29, 2012 at 16:45
  • Sorry should have made that clearer David Brown it contains a list of pointers –  RobBain85 Commented Apr 29, 2012 at 16:46

This could be an operator= implementation:

I don't know your ClassA 's instance variables, so you should implement the internal copying.

On the other hand, when iterating your list, you can copy objects this way:

(**p) returns, first the pointer stored in the iterator, and then dereferences it.

mfontanini's user avatar

  • would that mean i would have to copy each variable of the instance , lets say the class has 30+ variables then a =source.a b = source.b and so on –  RobBain85 Commented Apr 29, 2012 at 16:53
  • Yes, you would have to copy each variable. Anyway, there is a default assignment operator which does exactly that. You should only implement this operator if your class handles resources internally, like pointers, devices, etc. –  mfontanini Commented Apr 29, 2012 at 16:54
  • that worked a treat thank you very much fontanini, can you just explain a bit more about handling the resources internally if you don't mind, i don't quite follow ? –  RobBain85 Commented Apr 29, 2012 at 17:19
  • I'm glad it helped. You can read this stackoverflow thread which explains when you should implement copy assignment operator and the "rule of three": stackoverflow.com/questions/4172722/what-is-the-rule-of-three –  mfontanini Commented Apr 29, 2012 at 17:26

Your Answer

Reminder: Answers generated by artificial intelligence tools are not allowed on Stack Overflow. Learn more

Sign up or log in

Post as a guest.

Required, but never shown

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy .

Not the answer you're looking for? Browse other questions tagged c++ operator-overloading operator-keyword dynamic-arrays or ask your own question .

  • The Overflow Blog
  • The world’s largest open-source business has plans for enhancing LLMs
  • Featured on Meta
  • User activation: Learnings and opportunities
  • Site maintenance - Mon, Sept 16 2024, 21:00 UTC to Tue, Sept 17 2024, 2:00...
  • What does a new user need in a homepage experience on Stack Overflow?
  • Announcing the new Staging Ground Reviewer Stats Widget

Hot Network Questions

  • Is it really a "space walk" (EVA proper) if you don't get your feet wet (in space)?
  • Will there be Sanhedrin in Messianic Times?
  • Why does counterattacking lead to a more drawish and less dynamic position than defending?
  • How many engineers/scientists believed that human flight was imminent as of the late 19th/early 20th century?
  • Where are the DC-3 parked at KOPF?
  • What was the newest chess piece
  • What properties of the fundamental group functor are needed to uniquely determine it upto natural isomorphism?
  • Did the events of Mtt 16:16-20 actually take place on different occasions?
  • Is transit visa required for KSA if I am there for only 6 hours
  • Definition of annuity
  • Do carbon fiber wings need a wing spar?
  • Fast leap year check
  • How did people know that the war against the mimics was over?
  • Will "universal" SMPS work at any voltage in the range, even DC?
  • What factors cause differences between dried herb/spice brands?
  • Is it possible to draw this picture without lifting the pen? (I actually want to hang string lights this way in a gazebo without doubling up)
  • How to make a soundless world
  • Why do the shape/fluid loaders have three levels?
  • I am an imaginary variance
  • A word like "science/scientific" that can be used for ALL academic fields?
  • C++ std::function-like queue
  • What is the best way to protect from polymorphic viruses?
  • Would a scientific theory of everything be falsifiable?
  • The walk radical in Traditional Chinese

c overload assignment operator array

IMAGES

  1. Assignment Operator Overloading In C++

    c overload assignment operator array

  2. Overloading C++ "Assignment Operator =" with Example

    c overload assignment operator array

  3. Overloading assignment operator in C++

    c overload assignment operator array

  4. How to Overload Assignment Operator in C#

    c overload assignment operator array

  5. C++ Operator Overloading (With Examples)

    c overload assignment operator array

  6. Assignment Operator Overloading in C++

    c overload assignment operator array

VIDEO

  1. Inquirer Error

  2. Assignment Operator Overloading In C++

  3. Operators in C++

  4. Operator Overloading in C++

  5. C++ Tutorial 12 : Operator Overloading & File I/O

  6. Overloading operators

COMMENTS

  1. c++

    @K-ballo: His implementation, perhaps by accident, actually covers the problem of self assignment. It checks if the arrays are the same size. If they're not the same size, they can't be the same object.

  2. C++ Assignment Operator Overloading

    The assignment operator,"=", is the operator used for Assignment. It copies the right value into the left value. Assignment Operators are predefined to operate only on built-in Data types. Assignment operator overloading is binary operator overloading. Overloading assignment operator in C++ copies all values of one object to another object.

  3. 21.12

    21.12 — Overloading the assignment operator. Alex July 22, 2024. The copy assignment operator (operator=) is used to copy values from one object to another already existing object. As of C++11, C++ also supports "Move assignment". We discuss move assignment in lesson 22.3 -- Move constructors and move assignment.

  4. operator overloading

    In those situations where copy assignment cannot benefit from resource reuse (it does not manage a heap-allocated array and does not have a (possibly transitive) member that does, such as a member std::vector or std::string), there is a popular convenient shorthand: the copy-and-swap assignment operator, which takes its parameter by value (thus working as both copy- and move-assignment ...

  5. Assignment operators

    Correct behavior. CWG 1527. C++11. for assignments to class type objects, the right operand could be an initializer list only when the assignment is defined by a user-defined assignment operator. removed user-defined assignment constraint. CWG 1538. C++11. E1 ={E2} was equivalent to E1 = T(E2) (T is the type of E1), this introduced a C-style cast.

  6. Copy assignment operator

    the copy assignment operator selected for every non-static class type (or array of class type) member of T is trivial. A trivial copy assignment operator makes a copy of the object representation as if by std::memmove. All data types compatible with the C language (POD types) are trivially copy-assignable.

  7. C++ overloading array operator

    It is idiomatic to provide couple of overloads of the operator[] function - one for const objects and one for non-const objects. The return type of the const member function can be a const& or just a value depending on the object being returned while the return type of the non-const member function is usually a reference.. struct Heap{ int H[100]; int operator [] (int i) const {return H[i ...

  8. Operator Overloading, C++ FAQ

    It allows you to provide an intuitive interface to users of your class, plus makes it possible for templates to work equally well with classes and built-in/intrinsic types. Operator overloading allows C/C++ operators to have user-defined meanings on user-defined types (classes). Overloaded operators are syntactic sugar for function calls: class ...

  9. Overloading Subscript or array index operator [] in C++

    The range of a C++ array is from array[0] to array[size - 1]. However, C++ supports positive and negative subscripts. Negative subscripts must fall within array boundaries; if they do not, the results are unpredictable. ... Prerequisite: Operator Overloading The assignment operator,"=", is the operator used for Assignment. It copies the right ...

  10. Copy Constructor vs Assignment Operator in C++

    C++ compiler implicitly provides a copy constructor, if no copy constructor is defined in the class. A bitwise copy gets created, if the Assignment operator is not overloaded. Consider the following C++ program. Explanation: Here, t2 = t1; calls the assignment operator, same as t2.operator= (t1); and Test t3 = t1; calls the copy constructor ...

  11. c++

    This can result in changes done to one class object to affect all copies of this object. A solution to this can be to overload the = operator. Given the example below, with an attempt to create a dynamic array class, why does making changes to MyArray1 change MyArray2: Array Class: #include <iostream>.

  12. Overload resolution

    3) built-in candidates: For operator,, the unary operator &, and operator->, the set of built-in candidates is empty.For other operators built-in candidates are the ones listed in built-in operator pages as long as all operands can be implicitly converted to their parameters. If any built-in candidate has the same parameter list as a non-member candidate or rewritten non-member candidate ...

  13. operator overloading

    In those situations where copy assignment cannot benefit from resource reuse (it does not manage a heap-allocated array and does not have a (possibly transitive) member that does, such as a member std::vector or std::string), there is a popular convenient shorthand: the copy-and-swap assignment operator, which takes its parameter by value (thus working as both copy- and move-assignment ...

  14. 21.9

    Why operator[] returns a reference. Let's take a closer look at how list[2] = 3 evaluates. Because the subscript operator has a higher precedence than the assignment operator, list[2] evaluates first.list[2] calls operator[], which we've defined to return a reference to list.m_list[2].Because operator[] is returning a reference, it returns the actual list.m_list[2] array element.

  15. Overloading the Assignment operator for character Array in c++

    The C++ language does not allow defining operator overloads to anything other than classes. Some alternatives: Wrap the array as a member of a class and define assignment operator for that class. This is what std::array is, although it uses the implicit assignment operator which behaves differently from your operator (you cannot assign arrays ...

  16. Operator Overloading in C++

    Prerequisite: Operator Overloading The assignment operator,"=", is the operator used for Assignment. It copies the right value into the left value. Assignment Operators are predefined to operate only on built-in Data types. Assignment operator overloading is binary operator overloading.Overloading assignment operator in C++ copies all values of one

  17. operator overloading

    New operators such as **, <>, or &| cannot be created. The overloads of operators &&, ||, and , (comma) lose their special properties: short-circuit evaluation and sequencing. The overload of operator -> must either return a raw pointer or return an object (by reference or by value), for which operator -> is in turn overloaded.

  18. c++

    Assignment operator for dynamic array in C++. 0. Overloaded assignment operator with arrays. 0. Dynamic array implementaion c++ , Overloading assignment operator. Hot Network Questions `uname -r` shows kernel marked as `vmlinuz.old` in `/boot` partition