21.12 — Overloading the assignment operator

C++ Tutorial

  • C++ Overview
  • C++ Environment Setup
  • C++ Basic Syntax
  • C++ Comments
  • C++ Data Types
  • C++ Numeric Data Types
  • C++ Character Data Type
  • C++ Boolean Data Type
  • C++ Variable Types
  • C++ Variable Scope
  • C++ Multiple Variables
  • C++ Basic Input/Output
  • C++ Constants/Literals
  • C++ Modifier Types
  • C++ Storage Classes
  • C++ Operators
  • C++ Decision Making
  • C++ Loop Types
  • C++ Functions
  • C++ Numbers
  • C++ Strings
  • C++ String Length
  • C++ String Concatenation
  • C++ Pointers
  • C++ References
  • C++ Date & Time
  • C++ Structures
  • C++ Object Oriented
  • C++ Classes & Objects
  • C++ Inheritance
  • C++ Overloading
  • C++ Polymorphism
  • C++ Abstraction
  • C++ Encapsulation
  • C++ Interfaces
  • C++ Advanced
  • C++ Files and Streams
  • C++ Exception Handling
  • C++ Dynamic Memory
  • C++ Namespaces
  • C++ Templates
  • C++ Preprocessor
  • C++ Signal Handling
  • C++ Multithreading
  • C++ Web Programming
  • C++ - Advanced Concepts
  • C++ Useful Resources
  • C++ Questions and Answers
  • C++ Quick Guide
  • C++ Cheat Sheet
  • C++ STL Tutorial
  • C++ Standard Library
  • C++ Discussion
  • Selected Reading
  • UPSC IAS Exams Notes
  • Developer's Best Practices
  • Questions and Answers
  • Effective Resume Writing
  • HR Interview Questions
  • Computer Glossary

Assignment Operators Overloading in C++

You can overload the assignment operator (=) just as you can other operators and it can be used to create an object just like the copy constructor.

Following example explains how an assignment operator can be overloaded.

When the above code is compiled and executed, it produces the following result −

cppreference.com

Assignment operators.

(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)
General
(C++11)
(C++20)
(C++26)
(C++11)
(C++11)
-expression
-expression
-expression
(C++11)
(C++11)
(C++17)
(C++20)
    

Assignment operators modify the value of the object.

Operator name  Syntax  Prototype examples (for class T)
Inside class definition Outside class definition
simple assignment Yes T& T::operator =(const T2& b);
addition assignment Yes T& T::operator +=(const T2& b); T& operator +=(T& a, const T2& b);
subtraction assignment Yes T& T::operator -=(const T2& b); T& operator -=(T& a, const T2& b);
multiplication assignment Yes T& T::operator *=(const T2& b); T& operator *=(T& a, const T2& b);
division assignment Yes T& T::operator /=(const T2& b); T& operator /=(T& a, const T2& b);
remainder assignment Yes T& T::operator %=(const T2& b); T& operator %=(T& a, const T2& b);
bitwise AND assignment Yes T& T::operator &=(const T2& b); T& operator &=(T& a, const T2& b);
bitwise OR assignment Yes T& T::operator |=(const T2& b); T& operator |=(T& a, const T2& b);
bitwise XOR assignment Yes T& T::operator ^=(const T2& b); T& operator ^=(T& a, const T2& b);
bitwise left shift assignment Yes T& T::operator <<=(const T2& b); T& operator <<=(T& a, const T2& b);
bitwise right shift assignment Yes T& T::operator >>=(const T2& b); T& operator >>=(T& a, const T2& b);

this, and most also return *this so that the user-defined operators can be used in the same manner as the built-ins. However, in a user-defined operator overload, any type can be used as return type (including void). can be any type including .
Definitions Assignment operator syntax Built-in simple assignment operator Assignment from an expression Assignment from a non-expression initializer clause Built-in compound assignment operator Example Defect reports See also

[ edit ] Definitions

Copy assignment replaces the contents of the object a with a copy of the contents of b ( b is not modified). For class types, this is performed in a special member function, described in copy assignment operator .

replaces the contents of the object a with the contents of b, avoiding copying if possible (b may be modified). For class types, this is performed in a special member function, described in .

(since C++11)

For non-class types, copy and move assignment are indistinguishable and are referred to as direct assignment .

Compound assignment replace the contents of the object a with the result of a binary operation between the previous value of a and the value of b .

[ edit ] Assignment operator syntax

The assignment expressions have the form

target-expr new-value (1)
target-expr op new-value (2)
target-expr - the expression to be assigned to
op - one of *=, /= %=, += -=, <<=, >>=, &=, ^=, |=
new-value - the expression (until C++11) (since C++11) to assign to the target
  • ↑ target-expr must have higher precedence than an assignment expression.
  • ↑ new-value cannot be a comma expression, because its precedence is lower.

If new-value is not an expression, the assignment expression will never match an overloaded compound assignment operator.

(since C++11)

[ edit ] Built-in simple assignment operator

For the built-in simple assignment, the object referred to by target-expr is modified by replacing its value with the result of new-value . target-expr must be a modifiable lvalue.

The result of a built-in simple assignment is an lvalue of the type of target-expr , referring to target-expr . If target-expr is a bit-field , the result is also a bit-field.

[ edit ] Assignment from an expression

If new-value is an expression, it is implicitly converted to the cv-unqualified type of target-expr . When target-expr is a bit-field that cannot represent the value of the expression, the resulting value of the bit-field is implementation-defined.

If target-expr and new-value identify overlapping objects, the behavior is undefined (unless the overlap is exact and the type is the same).

If the type of target-expr is volatile-qualified, the assignment is deprecated, unless the (possibly parenthesized) assignment expression is a or an .

(since C++20)

new-value is only allowed not to be an expression in following situations:

is of a , and new-value is empty or has only one element. In this case, given an invented variable t declared and initialized as T t = new-value , the meaning of x = new-value  is x = t. is of class type. In this case, new-value is passed as the argument to the assignment operator function selected by .   <double> z; z = {1, 2}; // meaning z.operator=({1, 2}) z += {1, 2}; // meaning z.operator+=({1, 2})   int a, b; a = b = {1}; // meaning a = b = 1; a = {1} = b; // syntax error
(since C++11)

In overload resolution against user-defined operators , for every type T , the following function signatures participate in overload resolution:

& operator=(T*&, T*);
volatile & operator=(T*volatile &, T*);

For every enumeration or pointer to member type T , optionally volatile-qualified, the following function signature participates in overload resolution:

operator=(T&, T);

For every pair A1 and A2 , where A1 is an arithmetic type (optionally volatile-qualified) and A2 is a promoted arithmetic type, the following function signature participates in overload resolution:

operator=(A1&, A2);

[ edit ] Built-in compound assignment operator

The behavior of every built-in compound-assignment expression target-expr   op   =   new-value is exactly the same as the behavior of the expression target-expr   =   target-expr   op   new-value , except that target-expr is evaluated only once.

The requirements on target-expr and new-value of built-in simple assignment operators also apply. Furthermore:

  • For + = and - = , the type of target-expr must be an arithmetic type or a pointer to a (possibly cv-qualified) completely-defined object type .
  • For all other compound assignment operators, the type of target-expr must be an arithmetic type.

In overload resolution against user-defined operators , for every pair A1 and A2 , where A1 is an arithmetic type (optionally volatile-qualified) and A2 is a promoted arithmetic type, the following function signatures participate in overload resolution:

operator*=(A1&, A2);
operator/=(A1&, A2);
operator+=(A1&, A2);
operator-=(A1&, A2);

For every pair I1 and I2 , where I1 is an integral type (optionally volatile-qualified) and I2 is a promoted integral type, the following function signatures participate in overload resolution:

operator%=(I1&, I2);
operator<<=(I1&, I2);
operator>>=(I1&, I2);
operator&=(I1&, I2);
operator^=(I1&, I2);
operator|=(I1&, I2);

For every optionally cv-qualified object type T , the following function signatures participate in overload resolution:

& operator+=(T*&, );
& operator-=(T*&, );
volatile & operator+=(T*volatile &, );
volatile & operator-=(T*volatile &, );

[ edit ] Example

Possible output:

[ 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++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
C++11 E1 = {E2} was equivalent to E1 = T(E2)
( is the type of ), this introduced a C-style cast
it is equivalent
to E1 = T{E2}
C++20 compound assignment operators for volatile
-qualified types were inconsistently deprecated
none of them
is deprecated
C++11 an assignment from a non-expression initializer clause
to a scalar value would perform direct-list-initialization
performs copy-list-
initialization instead
C++20 bitwise compound assignment operators for volatile types
were deprecated while being useful for some platforms
they are not
deprecated

[ edit ] See also

Operator precedence

Operator overloading

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[...]
*a
&a
a->b
a.b
a->*b
a.*b

function call
a(...)
comma
a, b
conditional
a ? b : c
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)

for Assignment operators
  • 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 25 January 2024, at 23:41.
  • Privacy policy
  • About cppreference.com
  • Disclaimers

Powered by MediaWiki

C++ Operator Overloading Guidelines

One of the nice features of C++ is that you can give special meanings to operators, when they are used with user-defined classes. This is called operator overloading . You can implement C++ operator overloads by providing special member-functions on your classes that follow a particular naming convention. For example, to overload the + operator for your class, you would provide a member-function named operator+ on your class.

  • = (assignment operator)
  • + - * (binary arithmetic operators)
  • += -= *= (compound assignment operators)
  • == != (comparison operators)

Here are some guidelines for implementing these operators. These guidelines are very important to follow, so definitely get in the habit early.

Assignment Operator =

The assignment operator has a signature like this: class MyClass { public: ... MyClass & operator=(const MyClass &rhs); ... } MyClass a, b; ... b = a; // Same as b.operator=(a);

Notice that the = operator takes a const-reference to the right hand side of the assignment. The reason for this should be obvious, since we don't want to change that value; we only want to change what's on the left hand side.

  • e = 42 assigns 42 to e , then returns e as the result
  • The value of e is then assigned to d , and then d is returned as the result
  • The value of d is then assigned to c , and then c is returned as the result

Now, in order to support operator chaining, the assignment operator must return some value. The value that should be returned is a reference to the left-hand side of the assignment.

Notice that the returned reference is not declared const . This can be a bit confusing, because it allows you to write crazy stuff like this: MyClass a, b, c; ... (a = b) = c; // What?? At first glance, you might want to prevent situations like this, by having operator= return a const reference. However, statements like this will work with primitive types. And, even worse, some tools actually rely on this behavior. Therefore, it is important to return a non- const reference from your operator= . The rule of thumb is, "If it's good enough for int s, it's good enough for user-defined data-types."

So, for the hypothetical MyClass assignment operator, you would do something like this: // Take a const-reference to the right-hand side of the assignment. // Return a non-const reference to the left-hand side. MyClass& MyClass::operator=(const MyClass &rhs) { ... // Do the assignment operation! return *this; // Return a reference to myself. } Remember, this is a pointer to the object that the member function is being called on. Since a = b is treated as a.operator=(b) , you can see why it makes sense to return the object that the function is called on; object a is the left-hand side.

But, the member function needs to return a reference to the object, not a pointer to the object. So, it returns *this , which returns what this points at (i.e. the object), not the pointer itself. (In C++, instances are turned into references, and vice versa, pretty much automatically, so even though *this is an instance, C++ implicitly converts it into a reference to the instance.)

Now, one more very important point about the assignment operator:

YOU MUST CHECK FOR SELF-ASSIGNMENT!

This is especially important when your class does its own memory allocation. Here is why: The typical sequence of operations within an assignment operator is usually something like this: MyClass& MyClass::operator=(const MyClass &rhs) { // 1. Deallocate any memory that MyClass is using internally // 2. Allocate some memory to hold the contents of rhs // 3. Copy the values from rhs into this instance // 4. Return *this } Now, what happens when you do something like this: MyClass mc; ... mc = mc; // BLAMMO. You can hopefully see that this would wreak havoc on your program. Because mc is on the left-hand side and on the right-hand side, the first thing that happens is that mc releases any memory it holds internally. But, this is where the values were going to be copied from, since mc is also on the right-hand side! So, you can see that this completely messes up the rest of the assignment operator's internals.

The easy way to avoid this is to CHECK FOR SELF-ASSIGNMENT. There are many ways to answer the question, "Are these two instances the same?" But, for our purposes, just compare the two objects' addresses. If they are the same, then don't do assignment. If they are different, then do the assignment.

So, the correct and safe version of the MyClass assignment operator would be this: MyClass& MyClass::operator=(const MyClass &rhs) { // Check for self-assignment! if (this == &rhs) // Same object? return *this; // Yes, so skip assignment, and just return *this. ... // Deallocate, allocate new space, copy values... return *this; } Or, you can simplify this a bit by doing: MyClass& MyClass::operator=(const MyClass &rhs) { // Only do assignment if RHS is a different object from this. if (this != &rhs) { ... // Deallocate, allocate new space, copy values... } return *this; } Remember that in the comparison, this is a pointer to the object being called, and &rhs is a pointer to the object being passed in as the argument. So, you can see that we avoid the dangers of self-assignment with this check.

  • Take a const-reference for the argument (the right-hand side of the assignment).
  • Return a reference to the left-hand side, to support safe and reasonable operator chaining. (Do this by returning *this .)
  • Check for self-assignment, by comparing the pointers ( this to &rhs ).

Compound Assignment Operators += -= *=

I discuss these before the arithmetic operators for a very specific reason, but we will get to that in a moment. The important point is that these are destructive operators, because they update or replace the values on the left-hand side of the assignment. So, you write: MyClass a, b; ... a += b; // Same as a.operator+=(b) In this case, the values within a are modified by the += operator.

How those values are modified isn't very important - obviously, what MyClass represents will dictate what these operators mean.

The member function signature for such an operator should be like this: MyClass & MyClass::operator+=(const MyClass &rhs) { ... } We have already covered the reason why rhs is a const-reference. And, the implementation of such an operation should also be straightforward.

But, you will notice that the operator returns a MyClass -reference, and a non-const one at that. This is so you can do things like this: MyClass mc; ... (mc += 5) += 3;

Don't ask me why somebody would want to do this, but just like the normal assignment operator, this is allowed by the primitive data types. Our user-defined datatypes should match the same general characteristics of the primitive data types when it comes to operators, to make sure that everything works as expected.

This is very straightforward to do. Just write your compound assignment operator implementation, and return *this at the end, just like for the regular assignment operator. So, you would end up with something like this: MyClass & MyClass::operator+=(const MyClass &rhs) { ... // Do the compound assignment work. return *this; }

As one last note, in general you should beware of self-assignment with compound assignment operators as well. Fortunately, none of the C++ track's labs require you to worry about this, but you should always give it some thought when you are working on your own classes.

Binary Arithmetic Operators + - *

The binary arithmetic operators are interesting because they don't modify either operand - they actually return a new value from the two arguments. You might think this is going to be an annoying bit of extra work, but here is the secret:

Define your binary arithmetic operators using your compound assignment operators.

There, I just saved you a bunch of time on your homeworks.

So, you have implemented your += operator, and now you want to implement the + operator. The function signature should be like this: // Add this instance's value to other, and return a new instance // with the result. const MyClass MyClass::operator+(const MyClass &other) const { MyClass result = *this; // Make a copy of myself. Same as MyClass result(*this); result += other; // Use += to add other to the copy. return result; // All done! } Simple!

Actually, this explicitly spells out all of the steps, and if you want, you can combine them all into a single statement, like so: // Add this instance's value to other, and return a new instance // with the result. const MyClass MyClass::operator+(const MyClass &other) const { return MyClass(*this) += other; } This creates an unnamed instance of MyClass , which is a copy of *this . Then, the += operator is called on the temporary value, and then returns it.

If that last statement doesn't make sense to you yet, then stick with the other way, which spells out all of the steps. But, if you understand exactly what is going on, then you can use that approach.

You will notice that the + operator returns a const instance, not a const reference. This is so that people can't write strange statements like this: MyClass a, b, c; ... (a + b) = c; // Wuh...? This statement would basically do nothing, but if the + operator returns a non- const value, it will compile! So, we want to return a const instance, so that such madness will not even be allowed to compile.

  • Implement the compound assignment operators from scratch, and then define the binary arithmetic operators in terms of the corresponding compound assignment operators.
  • Return a const instance, to prevent worthless and confusing assignment operations that shouldn't be allowed.

Comparison Operators == and !=

The comparison operators are very simple. Define == first, using a function signature like this: bool MyClass::operator==(const MyClass &other) const { ... // Compare the values, and return a bool result. } The internals are very obvious and straightforward, and the bool return-value is also very obvious.

The important point here is that the != operator can also be defined in terms of the == operator, and you should do this to save effort. You can do something like this: bool MyClass::operator!=(const MyClass &other) const { return !(*this == other); } That way you get to reuse the hard work you did on implementing your == operator. Also, your code is far less likely to exhibit inconsistencies between == and != , since one is implemented in terms of the other.

How to Implement Assignment Operator Overloading in C++

  • How to Implement Assignment Operator …

How to Implement Assignment Operator Overloading in C++

This article will explain several methods of how to implement assignment operator overloading in C++.

Use copy-assignment operator to Implement Overloaded Assignment Operator in C++

C++ provides the feature to overload operators, a common way to call custom functions when a built-in operator is called on specific classes. These functions should have a special name starting with operator followed by the specific operator symbol itself. E.g., a custom assignment operator can be implemented with the function named operator= . Assignment operator generally should return a reference to its left-hand operand. Note that if the user does not explicitly define the copy assignment operator, the compiler generates one automatically. The generated version is quite capable when the class does not contain any data members manually allocated on the heap memory. It can even handle the array members by assigning each element to the corresponding object members. Although, it has shortcomings when dealing with dynamic memory data members, as shown in the following example code.

The above code defines only copy-constructor explicitly, which results in incorrect behavior when P1 object contents are assigned to the P3 object. Note that the second call to the P1.renamePerson function should not have modified the P3 object’s data members, but it did. The solution to this is to define an overloaded assignment operator i.e., copy-assignment operator. The next code snippet implements the version of the Person class that can copy assign the two objects of the same class correctly. Notice, though, the if statement in the copy-assignment function guarantees that the operator works correctly even when the object is assigned to itself.

Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

Related Article - C++ Class

  • How to Initialize Static Variables in C++ Class
  • How to Get Class Name in C++
  • Point and Line Class in C++
  • Class Template Inheritance in C++
  • Difference Between Structure and Class in C++
  • Wrapper Class in C++

Learn C++ practically and Get Certified .

Popular Tutorials

Popular examples, reference materials, learn c++ interactively, introduction to c++.

  • Getting Started With C++
  • Your First C++ Program
  • C++ Comments

C++ Fundamentals

  • C++ Keywords and Identifiers
  • C++ Variables, Literals and Constants
  • C++ Data Types
  • C++ Type Modifiers
  • C++ Constants
  • C++ Basic Input/Output
  • C++ Operators

Flow Control

  • C++ Relational and Logical Operators
  • C++ if, if...else and Nested if...else
  • C++ for Loop
  • C++ while and do...while Loop
  • C++ break Statement
  • C++ continue Statement
  • C++ goto Statement
  • C++ switch..case Statement

C++ Ternary Operator

  • C++ Functions
  • C++ Programming Default Arguments

C++ Function Overloading

  • C++ Inline Functions
  • C++ Recursion

Arrays and Strings

  • C++ Array to Function
  • C++ Multidimensional Arrays
  • C++ String Class

Pointers and References

  • C++ Pointers
  • C++ Pointers and Arrays
  • C++ References: Using Pointers
  • C++ Call by Reference: Using pointers
  • C++ Memory Management: new and delete

Structures and Enumerations

  • C++ Structures
  • C++ Structure and Function
  • C++ Pointers to Structure
  • C++ Enumeration

Object Oriented Programming

  • C++ Classes and Objects
  • C++ Constructors
  • C++ Constructor Overloading
  • C++ Destructors
  • C++ Access Modifiers
  • C++ Encapsulation
  • C++ friend Function and friend Classes

Inheritance & Polymorphism

  • C++ Inheritance
  • C++ Public, Protected and Private Inheritance
  • C++ Multiple, Multilevel and Hierarchical Inheritance
  • C++ Function Overriding
  • C++ Virtual Functions
  • C++ Abstract Class and Pure Virtual Function

STL - Vector, Queue & Stack

  • C++ Standard Template Library
  • C++ STL Containers
  • C++ std::array
  • C++ Vectors
  • C++ Forward List
  • C++ Priority Queue

STL - Map & Set

  • C++ Multimap
  • C++ Multiset
  • C++ Unordered Map
  • C++ Unordered Set
  • C++ Unordered Multiset
  • C++ Unordered Multimap

STL - Iterators & Algorithms

  • C++ Iterators
  • C++ Algorithm
  • C++ Functor

Additional Topics

  • C++ Exceptions Handling
  • C++ File Handling
  • C++ Ranged for Loop
  • C++ Nested Loop
  • C++ Function Template
  • C++ Class Templates
  • C++ Type Conversion
  • C++ Type Conversion Operators

C++ Operator Overloading

Advanced topics.

  • C++ Namespaces
  • C++ Preprocessors and Macros
  • C++ Storage Class
  • C++ Bitwise Operators
  • C++ Buffers
  • C++ istream
  • C++ ostream

C++ Tutorials

  • Subtract Complex Number Using Operator Overloading
  • Increment ++ and Decrement -- Operator Overloading in C++ Programming
  • Add Complex Numbers by Passing Structure to a Function

C++ Polymorphism

C++ Operator Precedence and Associativity

In C++, we can define how operators behave for user-defined types like class and structures . For example,

The + operator, when used with values of type int , returns their sum. However, when used with objects of a user-defined type, it is an error.

In this case, we can define the behavior of the + operator to work with objects as well.

This concept of defining operators to work with objects and structure variables is known as operator overloading .

  • Syntax for C++ Operator Overloading

The syntax for overloading an operator is similar to that of function with the addition of the operator keyword followed by the operator symbol.

  • returnType - the return type of the function
  • operator - a special keyword
  • symbol - the operator we want to overload ( + , < , - , ++ , etc.)
  • arguments - the arguments passed to the function
  • Overloading the Binary + Operator

Following is a program to demonstrate the overloading of the + operator for the class Complex .

Here, we first created a friend function with a return type Complex .

The operator keyword followed by + indicates that we are overloading the + operator.

The function takes two arguments:

  • Complex& indicates that we are passing objects by reference and obj1 and obj2 are references to Complex objects. This is an efficient approach because it avoids unnecessary copying, especially for large objects. To learn more, visit C++ References .
  • const indicates that referenced objects are constant, meaning we cannot modify obj1 and obj2 within the function.

Inside the function, we created another Complex object, temp to store the result of addition.

We then add the real parts of two objects and store it into the real attribute of the temp object.

Similarly, we add the imaginary parts of the two objects and store them into the img attribute of the temp object.

At last, we return the temp object from the function.

We can also overload the operators using a member function instead of a friend function. For example,

In this case, the operator is invoked by the first operand. Meaning, the line

translates to

Here, the number of arguments to the operator function is reduced by one because the first argument is used to invoke the function.

The problem with this approach is, not all the time the first operand is an object of a user-defined type. For example:

That's why it is recommended to overload operator functions as a non-member function generally, defined as a friend function.

  • Overloading ++ as a Prefix Operator

Following is a program to demonstrate the overloading of the ++ operator for the class Count .

Here, when we use ++count1; , the void operator ++ () is called. This increases the value attribute for the object count1 by 1.

Note : When we overload operators, we can use it to work in any way we like. For example, we could have used ++ to increase value by 100.

However, this makes our code confusing and difficult to understand. It's our job as a programmer to use operator overloading properly and in a consistent and intuitive way.

To overload the ++ operator as a Postfix Operator, we declare a member function operator++() with one argument having type int .

Here, when we use count1++; , the void operator ++ (int) is called. This increments the value attribute for the object count1 by 1.

Note : The argument int is just to indicate that the operator is used as a postfix operator.

  • Things to Remember in C++ Operator Overloading

1. By default, operators = and & are already overloaded in C++. For example,

we can directly use the = operator to copy objects of the same class. Here, we do not need to create an operator function.

2. We cannot change the precedence and associativity of operators using operator overloading.

3. We cannot overload following operators in C++:

  • :: (scope resolution)
  • . (member selection)
  • .* (member selection through pointer to function)
  • ?: (ternary operator)
  • sizeof operator
  • typeid Operator

4. We cannot overload operators for fundamental data types like int , float , etc

  • How to overload increment operator in right way?
  • How to overload binary operator - to subtract complex numbers?
  • Increment ++ and Decrement -- Operators

Table of Contents

  • Introduction

Sorry about that.

Our premium learning platform, created with over a decade of experience and thousands of feedbacks .

Learn and improve your coding skills like never before.

  • Interactive Courses
  • Certificates
  • 2000+ Challenges

Related Tutorials

C++ Tutorial

This browser is no longer supported.

Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.

General Rules for Operator Overloading

  • 7 contributors

The following rules constrain how overloaded operators are implemented. However, they do not apply to the new and delete operators, which are covered separately.

You cannot define new operators, such as . .

You cannot redefine the meaning of operators when applied to built-in data types.

Overloaded operators must either be a nonstatic class member function or a global function. A global function that needs access to private or protected class members must be declared as a friend of that class. A global function must take at least one argument that is of class or enumerated type or that is a reference to a class or enumerated type. For example:

The preceding code sample declares the less-than operator as a member function; however, the addition operators are declared as global functions that have friend access. Note that more than one implementation can be provided for a given operator. In the case of the preceding addition operator, the two implementations are provided to facilitate commutativity. It is just as likely that operators that add a Point to a Point , int to a Point , and so on, might be implemented.

Operators obey the precedence, grouping, and number of operands dictated by their typical use with built-in types. Therefore, there is no way to express the concept "add 2 and 3 to an object of type Point ," expecting 2 to be added to the x coordinate and 3 to be added to the y coordinate.

Unary operators declared as member functions take no arguments; if declared as global functions, they take one argument.

Binary operators declared as member functions take one argument; if declared as global functions, they take two arguments.

If an operator can be used as either a unary or a binary operator ( & , * , + , and - ), you can overload each use separately.

Overloaded operators cannot have default arguments.

All overloaded operators except assignment ( operator= ) are inherited by derived classes.

The first argument for member-function overloaded operators is always of the class type of the object for which the operator is invoked (the class in which the operator is declared, or a class derived from that class). No conversions are supplied for the first argument.

Note that the meaning of any of the operators can be changed completely. That includes the meaning of the address-of ( & ), assignment ( = ), and function-call operators. Also, identities that can be relied upon for built-in types can be changed using operator overloading. For example, the following four statements are usually equivalent when completely evaluated:

This identity cannot be relied upon for class types that overload operators. Moreover, some of the requirements implicit in the use of these operators for basic types are relaxed for overloaded operators. For example, the addition/assignment operator, += , requires the left operand to be an l-value when applied to basic types; there is no such requirement when the operator is overloaded.

For consistency, it is often best to follow the model of the built-in types when defining overloaded operators. If the semantics of an overloaded operator differ significantly from its meaning in other contexts, it can be more confusing than useful.

Operator Overloading

Was this page helpful?

Additional resources

lock

Unlock this article for Free, by logging in

Don’t worry, unlock all articles / blogs on PrepInsta by just simply logging in on our website

Assignment Operator Overloading in C++

February 8, 2023

What is assignment operator overloading in C++?

The assignment operator is a binary operator that is used to assign the value to the variables. It is represented by equal to symbol(=). It copies the right value into the left value i.e the value that is on the right side of equal to into the variable that is on the left side of equal to.

Assignment Operator Overloading in C++

Overloading assignment operator in C++

  • Overloading assignment operator in C++ copies all values of one object to another object.
  • The object from which values are being copied is known as an instance variable.
  • A non-static member function should be used to overload the assignment operator.

The compiler generates the function to overload the assignment operator if the function is not written in the class. The overloading assignment operator can be used to create an object just like the copy constructor. If a new object does not have to be created before the copying occurs, the assignment operator is used, and if the object is created then the copy constructor will come into the picture. Below is a program to explain how the assignment operator overloading works.

C++ Introduction

History of C++

Structure of a C++ Program

String in C++

Program to check armstrong number or not

C++ program demonstrating assignment operator overloading

Prime course trailer, related banners.

Get PrepInsta Prime & get Access to all 200+ courses offered by PrepInsta in One Subscription

overloading the assignment operator

Get over 200+ course One Subscription

Courses like AI/ML, Cloud Computing, Ethical Hacking, C, C++, Java, Python, DSA (All Languages), Competitive Coding (All Languages), TCS, Infosys, Wipro, Amazon, DBMS, SQL and others

Checkout list of all the video courses in PrepInsta Prime Subscription

Login/Signup to comment

overloading the assignment operator

30+ Companies are Hiring

Get Hiring Updates right in your inbox from PrepInsta

  • 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.

C# Corner

  • TECHNOLOGIES
  • An Interview Question

Python

Introduction to Python Operators

overloading the assignment operator

  • Baibhav Kumar
  • Aug 30, 2024
  • Other Artcile

This article explains Python operators, covering arithmetic, comparison, logical, bitwise, membership, identity, and operator overloading. It includes examples for each, emphasizing their importance in performing operations and comparisons.

In Python, operators are symbols that tell the program to perform specific operations on values or variables. They help you add numbers, compare values, or manipulate data. There are different types of operators, like those for math, comparing things, working with bits, and even creating custom actions. In this guide, we'll break down these operators into simple explanations so you can easily understand how they work.

Python Arithmetic Operators

Arithmetic operators provide a set of operators to perform basic mathematical operations:

  • Addition (+): This operator adds two values together.
  • Subtraction (-): Subtracts one value from another.
  • Multiplication (*): Multiplies two values.
  • Division (/): Divides one value by another, resulting in a floating-point number.
  • Floor Division (//): Divides two values and returns the largest integer less than or equal to the result.
  • Exponentiation (**): Raises one value to the power of another.
  • Modulus (%): Returns the remainder after dividing one value by another.

Python Arithmetic Operators Output

Python Comparison Operators

Comparison operators help compare values and return either True or False. These operators include:

  • Greater Than (>): Checks if the value on the left is greater than the value on the right.
  • Less Than (<): Check if the value on the left is less than the value on the right.
  • Equal To (==): Checks if both values are equal.
  • Not Equal To (!=): Checks if both values are not equal.
  • Greater Than or Equal To (>=): Check if the value on the left is greater than or equal to the value on the right.
  • Less Than or Equal To (<=): Check if the value on the left is less than or equal to the value on the right.

Comparison operators are vital for controlling program flow, particularly in decision-making scenarios like if statements and loops.

Python Comparison Operators

Python Logical Operators

Python logical operators are used to perform logical operations on boolean values, returning either True or False. They are primarily used in conditional statements to combine or negate conditions.

  • and: Returns True if both operands are True; otherwise, it returns False.
  • or: Returns True if at least one of the operands is True; returns False only if both are False.
  • not: Negates the boolean value; if the value is True, it returns False, and vice versa.

Logical operators are used to create complex conditions, enabling more flexible and sophisticated decision-making in programs.

Python Logical Operators

Python Bitwise Operators

Bitwise operators in Python work at the bit level, meaning they perform operations on the binary representation of numbers. These operators manipulate individual bits of data, which can be useful for low-level programming tasks like handling binary data or optimizing performance.

  • & (AND): Compares each bit of two numbers. If both bits are 1, the result is 1. Otherwise, it's 0.
  • | (OR): Compares each bit of two numbers. If at least one bit is 1, the result is 1. If both are 0, the result is 0.
  • ^ (XOR): Compares each bit of two numbers. If the bits are different, the result is 1. If they are the same, the result is 0.
  • ~ (NOT): Flips all the bits of a number, turning 1s into 0s and 0s into 1s.
  • << (Left Shift): Shifts the bits of a number to the left by a specified number of positions, effectively multiplying the number by powers of two.
  • >> (Right Shift): Shifts the bits of a number to the right by a specified number of positions, effectively dividing the number by powers of two.

Bitwise operators are often used in scenarios where performance and memory efficiency are critical, such as in systems programming, cryptography, or data compression.

Python Bitwise Operators

Python Membership Operators

Membership operators in Python are used to check if a value is part of a sequence, such as a list, tuple, string, or set. These operators help determine whether a particular item exists within a collection.

  • in: This operator checks if a value exists in a sequence. If the value is found, it returns True; otherwise, it returns False.
  • not in: This operator checks if a value does not exist in a sequence. If the value is not found, it returns True; otherwise, it returns False.

Membership operators are commonly used in conditions or loops to verify the presence or absence of elements in data structures like lists, strings, or dictionaries. For example, you might check if a user’s input exists in a predefined list of valid options.

Python Membership Operators

Python Identity Operators

Identity operators in Python are used to compare the memory locations of two objects. They check whether two variables refer to the same object in memory, rather than just having equal values.

  • is: This operator returns True if two variables point to the same object in memory, meaning they are identical.
  • is not: This operator returns True if two variables do not point to the same object in memory, meaning they are not identical.

Identity operators are helpful when you need to check if two variables reference the same object, particularly when dealing with mutable objects like lists or dictionaries. For instance, in cases where you want to avoid unintentional modifications to a shared object.

Python Identity Operators

Operator overloading in Python allows you to change how operators like +, -, and * work with your custom objects. Normally, these operators work with basic data types like numbers, but with operator overloading, you can define what they do when applied to your objects.

  • Customizing Operators: You can change how operators like +, -, and == behave when used with your objects by defining special methods in your class.
  • Make Objects Behave Like Built-in Types: This allows your objects to interact with operators in a way that feels natural, just like numbers or strings do.
  • Simplifies Complex Data Structures: It is helpful for creating more intuitive code when working with complex objects like matrices, vectors, or custom data types.

Python Operator Overloading Example 2 Output

To write effective Python code, it's important to understand different operators, like those for math, logic, bitwise operations, checking membership, and comparing identity. Python also lets you extend these operators to work with custom objects, making the language more powerful. Whether you're doing calculations or comparing items, operators are a key part of Python that you'll use often.

  • Operator Overloading

C# Corner Ebook

Coding Principles

overloading the assignment operator

Announcing the Proxy 3 Library for Dynamic Polymorphism

Mingxin Wang

We are thrilled to announce that Proxy 3 , our latest and greatest solution for polymorphism in C++, is now feature complete ! Since the library was initially open-sourced , we have heard much positive feedback and received many brilliant feature requests. Big thanks to all of you who have contributed any code or idea that made the library better!

Our Mission

“Proxy” is a modern C++ library that helps you use polymorphism (a way to use different types of objects interchangeably) without needing inheritance.

“Proxy” was created by Microsoft engineers and has been used in the Windows operating system since 2022. For many years, using inheritance was the main way to achieve polymorphism in C++. However, new programming languages like Rust offer better ways to do this. We have improved our understanding of object-oriented programming and decided to use pointers in C++ as the foundation for “Proxy”. Specifically, the “Proxy” library is designed to be:

  • Portable : “Proxy” was implemented as a single-header library in standard C++20. It can be used on any platform while the compiler supports C++20. The majority of the library is freestanding , making it feasible for embedded engineering or kernel design of an operating system.
  • Non-intrusive : An implementation type is no longer required to inherit from an abstract binding.
  • Well-managed : “Proxy” provides a GC -like capability that manages the lifetimes of different objects efficiently without the need for an actual garbage collector.
  • Fast : With typical compiler optimizations, “Proxy” produces high-quality code that is as good as or better than hand-written code. In many cases, “Proxy” performs better than traditional inheritance-based approaches, especially in managing the lifetimes of objects.
  • Accessible : Learned from user feedback, accessibility has been significantly improved in “Proxy 3” with intuitive syntax, good IDE compatibility, and accurate diagnostics.
  • Flexible : Not only member functions, the “abstraction” of “Proxy” allows any expression to be polymorphic, including free functions, operators, conversions, etc. Different abstractions can be freely composed on demand. Performance tuning is supported for experts to balance between extensibility and performance.

The New Look

Comparing to our previous releases, there are some major improvements in the syntax and utilities. Let’s get started with some examples!

Hello World

Here is a step-by-step explanation:

  • #include <iostream> : For std::cout .
  • #include <string> : For std::string .
  • #include "proxy.h" : For the “Proxy” library. Most of the facilities of the library are defined in namespace pro . If the library is consumed via vcpkg or conan , this line should be changed into #include <proxy/proxy.h> .
  • pro::facade_builder : Provides capability to build a facade type at compile-time.
  • add_convention : Adds a generalized “calling convention”, defined by a “dispatch” and several “overloads”, to the build context.
  • pro::operator_dispatch<"<<", true> : Specifies a dispatch for operator << expressions where the primary operand ( proxy ) is on the right-hand side (specified by the second template parameter true ). Note that polymorphism in the “Proxy” library is defined by expressions rather than member functions, which is different from C++ virtual functions or other OOP languages.
  • std::ostream&(std::ostream& out) const : The signature of the calling convention, similar with std::move_only_function . const specifies that the primary operand is const .
  • build : Builds the context into a facade type.
  • pro::proxy<Streamable> p1 = &str : Creates a proxy object from a raw pointer of std::string . p1 behaves like a raw pointer, and does not have ownership of the underlying std::string . If the lifetime of str ends before p1 , p1 becomes dangling.
  • std::cout << *p1 : This is how it works. It prints “Hello World” because the calling convention is defined in the facade Streamable , so it works as if by calling std::cout << str .
  • pro::proxy<Streamable> p2 = std::make_unique <int>(123) : Creates a std::unique_ptr <int> and converts to a proxy . Different from p1 , p2 has ownership of the underlying int because it is instantiated from a value of std::unique_ptr , and will call the destructor of std::unique_ptr when p2 is destroyed, while p1 does not have ownership of the underlying int because it is instantiated from a raw pointer. p1 and p2 are of the same type pro::proxy<Streamable> , which means you can have a function that returns pro::proxy<Streamable> without exposing any information about the implementation details to its caller.
  • std::cout << *p2 : Prints “123” with no surprise.
  • Similar with p2 , p3 also has ownership of the underlying double value, but can effectively avoid heap allocation.
  • Since the size of the underlying type ( double ) is known to be small (on major 32- or 64-bit platforms), pro::make_proxy realizes the fact at compile-time and guarantees no heap allocation.
  • Library “Proxy” explicitly defines when heap allocation occurs or not to avoid users falling into performance hell, which is different from std::function and other existing polymorphic wrappers in the standard.
  • std::cout << *p3 : Prints “3.14” with no surprise.
  • When main returns, p2 and p3 will destroy the underlying objects, while p1 does nothing because it holds a raw pointer that does not have ownership of the underlying std::string .

More Expressions

In addition to the operator expressions demonstrated in the previous example, the library supports almost all forms of expressions in C++ and can make them polymorphic. Specifically,

  • The PRO_DEF_MEM_DISPATCH macro: Defines a dispatch type for member function call expressions.
  • The PRO_DEF_FREE_DISPATCH macro: Defines a dispatch type for free function call expressions.
  • The pro::operator_dispatch class template: Dispatch type for operator expressions.
  • The pro::conversion_dispatch class template: Dispatch type for conversion expressions.

Note that some facilities are provided as macros, because C++ templates today do not support generating a function with an arbitrary name. Here is another example that makes member function call expressions polymorphic:

  • #include <sstream> : For std::stringstream .
  • #include "proxy.h" : For the “Proxy” library.
  • PRO_DEF_MEM_DISPATCH(MemDraw, Draw) : Defines a dispatch type MemDraw for expressions of calling member function Draw .
  • PRO_DEF_MEM_DISPATCH(MemArea, Area) : Defines a dispatch type MemArea for expressions of calling member function Area .
  • add_convention : Adds calling conventions to the build context.
  • support_copy<pro::constraint_level::nontrivial> : Specifies the underlying pointer type shall be copyable, which also makes the resulting proxy type copyable.
  • class Rectangle : An implementation of Drawable .
  • Function PrintDrawableToString : Converts a Drawable into a std::string . Note that this is a function rather than a function template, which means it can generate ABI in a larger build system.
  • pro::proxy<Drawable> p = pro::make_proxy<Drawable, Rectangle>(3, 5) : Creates a proxy<Drawable> object containing a Rectangle .
  • std::string str = PrintDrawableToString(p) : Converts p into a std::string , implicitly creates a copy of p .
  • std::cout << str : Prints the string.

Other Useful Features

In addition to the features mentioned above, here is a curated list of the most popular features based on user feedback:

  • Overloading : facade_builder::add_convention is more powerful than demonstrated above. It can take any number of overload types and perform standard overload resolution when invoking a proxy .
  • Facade composition : facade_builder::add_facade allows flexible composition of different abstractions.
  • Weak dispatch : When an object does not implement a convention, and we do not want it to trigger a hard compile error, it is allowed to define a “weak dispatch” with macro PRO_DEF_WEAK_DISPATCH from an existing dispatch type and a default implementation.
  • Allocator awareness : Function template allocate_proxy is able to create a proxy from a value with any custom allocator. In C++11, std::function and std::packaged_task had constructors that accepted custom allocators for performance tuning, but these were removed in C++17 because “the semantics are unclear, and there are technical issues with storing an allocator in a type-erased context and then recovering that allocator later for any allocations needed during copy assignment”. These issues do not apply to allocate_proxy .
  • Configurable constraints : facade_builder provides full support for constraints configuration, including memory layout (by restrict_layout ), copyability (by support_copy ), relocatability (by support_relocation ), and destructibility (by support_destruction ).
  • Reflection : proxy supports type-based compile-time reflection for runtime queries, specifically with facade_builder::add_reflection and function template proxy_reflect .

We hope this library could empower more C++ users outside Microsoft to write polymorphic code easier. The full documentation of Proxy 3 will be published soon. Please stay tuned for more technical details. We are also actively working on several ISO C++ proposals for further standardization.

Leave a comment Cancel reply

to start the discussion. Sign in

Insert/edit link

Enter the destination URL

Or link to existing content

  • C++ Data Types
  • C++ Input/Output
  • C++ Pointers
  • C++ Interview Questions
  • C++ Programs
  • C++ Cheatsheet
  • C++ Projects
  • C++ Exception Handling
  • C++ Memory Management

Types of Operator Overloading in C++

C++ provides a special function to change the current functionality of some operators within its class which is often called as operator overloading. Operator Overloading is the method by which we can change some specific operators’ functions to do different tasks.

  • Return_Type is the value type to be returned to another object.
  • operator op is the function where the operator is a keyword.
  • op is the operator to be overloaded.

Operator Overloading can be done by using two approaches , i.e.

  • Overloading Unary Operator.
  • Overloading Binary Operator .

Criteria/Rules to Define the Operator Function

  • In the case of a non-static member function , the binary operator should have only one argument and the unary should not have an argument.
  • In the case of a friend function , the binary operator should have only two arguments and the unary should have only one argument.
  • Operators that cannot be overloaded are   .* :: ?:
  • Operators that cannot be overloaded when declaring that function as friend function are = () [] -> .
  • The operator function must be either a non-static (member function), global free function or a friend function.

Refer to this, for more rules of Operator Overloading .

1. Overloading Unary Operator

Let us consider overloading (-) unary operator. In the unary operator function, no arguments should be passed. It works only with one class object. It is the overloading of an operator operating on a single operand.

Example: Assume that class Distance takes two member objects i.e. feet and inches, and creates a function by which the Distance object should decrement the value of feet and inches by 1 (having a single operand of Distance Type). 

Explanation: In the above program, it shows that no argument is passed and no return_type value is returned, because the unary operator works on a single operand. (-) operator changes the functionality to its member function.

Note:  d2 = -d1 will not work, because operator-() does not return any value.

2. Overloading Binary Operator

In the binary operator overloading function, there should be one argument to be passed. It is the overloading of an operator operating on two operands. Below is the C++ program to show the overloading of the binary operator (+) using a class Distance with two distant objects. 

Explanation:

  • Line 27, Distance operator+(Distance &d2): Here return type of function is distance and it uses call by references to pass an argument. 
  • Line 49, d3 = d1 + d2: Here, d1 calls the operator function of its class object and takes d2 as a parameter, by which the operator function returns the object and the result will reflect in the d3 object.

Pictorial View of working of Binary Operator

Working of Binary Operator

In these ways, an operator can be overloaded to perform certain tasks by changing the functionality of operators.

author

Please Login to comment...

Similar reads.

  • Technical Scripter
  • cpp-operator
  • cpp-operator-overloading
  • How to Delete Discord Servers: Step by Step Guide
  • Google increases YouTube Premium price in India: Check our the latest plans
  • California Lawmakers Pass Bill to Limit AI Replicas
  • Best 10 IPTV Service Providers in Germany
  • 15 Most Important Aptitude Topics For Placements [2024]

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.

Is there a workaround for overloading the assignment operator in C#?

Unlike C++, in C# you can't overload the assignment operator.

I'm doing a custom Number class for arithmetic operations with very large numbers and I want it to have the look-and-feel of the built-in numerical types like int, decimal, etc. I've overloaded the arithmetic operators, but the assignment remains...

Here's an example:

Is there a workaround for that issue?

  • operator-overloading

Steve's user avatar

  • 2 Explain the issue (why you need it). –  Shog9 Commented Nov 15, 2008 at 15:37
  • Sorry, maybe I should've been more specific. I'm doing a custom Number class for arithmetic operations with very large numbers and I want it to have the look-and-feel of the built-in numerical types like int, decimal, etc. I've overloaded the arithmetic operators, but the assignment remains... –  Jon Galloway Commented Nov 15, 2008 at 16:13
  • Thanks - i've added your comment to the question itself. –  Shog9 Commented Nov 15, 2008 at 16:15
  • 1 Here's an example: Number a = new Number(55); Number b = a; And I want it to copy the value, not the reference. –  Jon Galloway Commented Nov 15, 2008 at 16:21
  • 2 Look at DateTime and TimeSpan. Plenty of methods there. If it's effectively an atomic value, then it should probably be a struct. Numbers almost always fall into this category. –  Jon Skeet Commented Nov 15, 2008 at 17:10

7 Answers 7

you can use the 'implicit' keyword to create an overload for the assignment:

Suppose you have a type like Foo, that you feel is implicitly convertable from a string. You would write the following static method in your Foo class:

Having done that, you can then use the following in your code:

Jonathan Wood's user avatar

  • 2 Cool, this answers a question I was going ot ask ;) –  Sam Salisbury Commented Apr 20, 2010 at 14:35
  • 3 Doesn't that only work if you are trying to assign one type to another? It's an implicit cast, after all. I don't think that would help if you wanted to assign Number to Number . –  Drew Noakes Commented Jun 5, 2010 at 6:51
  • @Jonathan Wood - That was exactly what i was looking for! Much appreciated! –  Steven Magana-Zook Commented Jun 10, 2011 at 23:45
  • @drew-noakes: If you want to assign Number to Number, and Number is a struct, you get the desired effect with the default assignment operator anyway: Assign by value. –  Nilzor Commented Aug 3, 2011 at 11:21
  • @Nilzor, in such a case you get a copy of the value as you say, but the OP wants to control that process somehow with their own code. I don't think that's possible unless you're adapting between two types. So it's slightly different to what you can do in C++. –  Drew Noakes Commented Aug 3, 2011 at 11:44

It's still not at all clear to me that you really need this. Either:

  • Your Number type should be a struct (which is probable - numbers are the most common example of structs). Note that all the types you want your type to act like (int, decimal etc) are structs.
  • Your Number type should be immutable, making every mutation operation return a new instance, in which case you don't need the data to be copied on assignment anyway. (In fact, your type should be immutable whether or not it's a struct. Mutable structs are evil, and a number certainly shouldn't be a mutable reference type.)

Jon Skeet's user avatar

  • Yes, maybe the struct idea is good. And I like the immutability option - it was suggested in another answer. Thanks, I'll try what you propose. –  Jon Galloway Commented Nov 15, 2008 at 17:03
  • 1 Mutable structs might be evil but the C# team thought they were ok for Enumerators. I think it's more correct to say it as a general rule. –  Razor Commented May 16, 2011 at 4:57
  • 3 Mutability is not evil, if you can prevent object sharing. This can be done by implementing linear types which requires some form of assignment overloading. en.wikipedia.org/wiki/Linear_type_system . –  cdiggins Commented Apr 13, 2012 at 15:30

You won't be able to work around it having the C++ look, since a = b; has other semantics in C++ than in C#. In C#, a = b; makes a point to the same object like b. In C++, a = b changes the content of a. Both has their ups and downs. It's like you do

In C++ (it will lose the reference to the first object, and create a memory leak. But let's ignore that here). You cannot overload the assign operator in C++ for that either.

The workaround is easy:

Disclaimer : I'm not a C# developer

You could create a write-only-property like this. then do a.Self = b; above.

Now, this is not good. Since it violates the principle-of-least-surprise (POLS). One wouldn't expect a to change if one does a.Self = b;

Johannes Schaub - litb's user avatar

  • Maybe I could do it that way. But what I meant was - a workaround that gives me the real look-and-feel of assignment operator overloading, so I ca literally say: MyType a = new MyType(); MyType b = new MyType(); a = b; and it performs some custom assignment logic. –  Jon Galloway Commented Nov 15, 2008 at 15:54
  • The description of why it doesn't work is spot-on. As you suggest, though, the Self property idea is not so good, –  Charlie Commented Nov 15, 2008 at 16:09
  • "In C++, a = b changes the content of a." - thats not entirely correct. it depends on whether a and b are pointers or not. a=b could make a point to b or it could call your = overload and copy the contents to a. –  user585968 Commented Feb 22, 2012 at 9:47
  • 1 @MickyDuncan Eh.. it is entirely correct. What do you think the content of a and b IS if they are pointers? In what sense does "only copying the pointer" differ from "copying the content" when the content IS a pointer? –  The Dag Commented Nov 6, 2012 at 10:32
  • @TheDag c++ = assignment can either make a pointer point to the same object OR change the contents depending on the variable type. One did not establish we were talking about just pointers –  user585968 Commented Nov 7, 2012 at 2:54

Instead of making a copy of the data when passing the reference you could make the class immutable. When the class is immutable having multiple references to it isn't a problem since it can't be changed.

Operations that changes the data would of course return new instances.

Cristian Libardo's user avatar

An earlier post suggested this:

public static implicit operator Foo(string normalString) { }

I tried this approach... but to make it work you need this:

public static implicit operator Foo(Foo original) { }

and the compiler won't let you have an implicit conversion function from your exact type, nor from any base type of yourself. That makes sense since it would be a backdoor way of overriding the assignment operator, which C# doesn't want to allow.

DMC's user avatar

  • "The implicit keyword is used to declare an implicit user-defined type conversion operator. Use it to enable implicit conversions between a user-defined type and another type, ..." - MSDN –  user585968 Commented Feb 22, 2012 at 9:50

Here is a solution that worked for myself :

Somewhere else in the code :

ttrixas's user avatar

Maybe what you're looking for can be solved using C# accessors.

http://msdn.microsoft.com/en-us/library/aa287786(v=vs.71).aspx

TDot's user avatar

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 .

  • The Overflow Blog
  • At scale, anything that could fail definitely will
  • Best practices for cost-efficient Kafka clusters
  • Featured on Meta
  • Announcing a change to the data-dump process
  • Bringing clarity to status tag usage on meta sites
  • What does a new user need in a homepage experience on Stack Overflow?
  • Feedback requested: How do you use tag hover descriptions for curating and do...
  • Staging Ground Reviewer Motivation

Hot Network Questions

  • Convert 8 Bit brainfuck to 1 bit Brainfuck / Boolfuck
  • micro usb is not giving 5v but instead vbus is giving 0.45v
  • Has any astronomer ever observed that after a specific star going supernova it became a Black Hole?
  • Why is there so much salt in cheese?
  • Does a representation of the universal cover of a Lie group induce a projective representation of the group itself?
  • What is Zion's depth in the Matrix?
  • In Lord Rosse's 1845 drawing of M51, was the galaxy depicted in white or black?
  • Why are poverty definitions not based off a person's access to necessities rather than a fixed number?
  • Using rule-based symbology for overlapping layers in QGIS
  • Can a British judge convict and sentence someone for contempt in their own court on the spot?
  • How do I safely download and run an older version of software for testing without interfering with the currently installed version?
  • Movie from 80s or 90s about a helmet which allowed to detect non human people
  • Why is a USB memory stick getting hotter when connected to USB-3 (compared to USB-2)?
  • What is the difference between negation-eliminiation ¬E and contradiction-introduction ⊥I?
  • Is it possible to draw a series of mutually perpendicular curves in TikZ?
  • The state of the art on topological rings - the Jacobson topology
  • How to resolve this calculation prompt that appears after running the drawing program?
  • "The earth was formless and void" Did the earth exist before God created the world?
  • Is loss of availability automatically a security incident?
  • How to Include Mathematical Expressions like \sqrt{8} Inside \qty Command with siunitx?
  • Can a quadrilateral polygon have 3 obtuse angles?
  • Escape from the magic prison
  • Possible thermal insulator to allow Unicellular organisms to survive a Venus like environment?
  • Creating Layout of 2D Board game

overloading the assignment operator

IMAGES

  1. Overloading Assignment Operator

    overloading the assignment operator

  2. Overloading Operator MySting Example

    overloading the assignment operator

  3. C++ Operator Overloading (With Examples)

    overloading the assignment operator

  4. Assignment Operator Overloading In C++

    overloading the assignment operator

  5. Overloading assignment operator in C++

    overloading the assignment operator

  6. C++ Overloading the Assignment Operator [4]

    overloading the assignment operator

VIDEO

  1. Learn Advanced C++ Programming overloading the assignment operator

  2. Complex No. Addition & Multiplication Using Operator Overloading

  3. 13.9 Overloading assignment operator

  4. Operator overloading

  5. (11) OOP244 NAA

  6. Lecture on operator overloading: complex number example

COMMENTS

  1. 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 .

  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. assignment operator overloading in c++

    There are no problems with the second version of the assignment operator. In fact, that is the standard way for an assignment operator. Edit: Note that I am referring to the return type of the assignment operator, not to the implementation itself. As has been pointed out in comments, the implementation itself is another issue.

  4. Assignment Operators Overloading in C++

    You can overload the assignment operator (=) just as you can other operators and it can be used to create an object just like the copy constructor. Following example explains how an assignment operator can be overloaded. feet = 0; inches = 0; } Distance(int f, int i) {. feet = f; inches = i; } void operator = (const Distance &D ) {.

  5. operator overloading

    Commonly overloaded operators have the following typical, canonical forms: 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 be safe on self-assignment, and to return the lhs by reference:

  6. When should we write our own assignment operator in C++?

    1) Do not allow assignment of one object to other object. We can create our own dummy assignment operator and make it private. 2) Write your own assignment operator that does deep copy. Same is true for Copy Constructor. Following is an example of overloading assignment operator for the above class. #include<iostream>.

  7. Operator Overloading in C++

    Assignment operator overloading is binary operator overloading.Overloading assignment operator in C++ copies all values of one. 4 min read. deque::operator= and deque::operator[] in C++ STL. Deque or Double ended queues are sequence containers with the feature of expansion and contraction on both the ends. They are similar to vectors, but are ...

  8. 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.

  9. C++ Operator Overloading Guidelines

    The following set of operators is commonly overloaded for user-defined classes: = (assignment operator) + - * (binary arithmetic operators) += -= *= (compound assignment operators) == != (comparison operators) Here are some guidelines for implementing these operators. These guidelines are very important to follow, so definitely get in the habit ...

  10. How to Implement Assignment Operator Overloading in C++

    The solution to this is to define an overloaded assignment operator i.e., copy-assignment operator. The next code snippet implements the version of the Person class that can copy assign the two objects of the same class correctly. Notice, though, the if statement in the copy-assignment function guarantees that the operator works correctly even ...

  11. Best way to overload the C++ assignment operator

    Usually, the best way to implement a copy assignment operator is to provide a swap() function for your class (or use the standard one if it does what you want) and then implement the copy assignment operator via the copy constructor:

  12. Operator Overloading

    Overloaded operators are implemented as functions. The name of an overloaded operator is operator x, where x is the operator as it appears in the following table. For example, to overload the addition operator, you define a function called operator+. Similarly, to overload the addition/assignment operator, +=, define a function called operator+=.

  13. C++ Operator Overloading (With Examples)

    Things to Remember in C++ Operator Overloading. 1. By default, operators = and & are already overloaded in C++. For example, we can directly use the = operator to copy objects of the same class. Here, we do not need to create an operator function. 2. We cannot change the precedence and associativity of operators using operator overloading. 3 ...

  14. General Rules for Operator Overloading

    All overloaded operators except assignment (operator=) are inherited by derived classes. The first argument for member-function overloaded operators is always of the class type of the object for which the operator is invoked (the class in which the operator is declared, or a class derived from that class). No conversions are supplied for the ...

  15. Overloading assignment operator in C#

    There is already a special instance of overloading = in place that the designers deemed ok: property setters. Let X be a property of foo. In foo.X = 3, the = symbol is replaced by the compiler by a call to foo.set_X(3). You can already define a public static T op_Assign(ref T assigned, T assignee) method.

  16. Copy Constructor vs Assignment Operator 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. Assignment Operator Overloading in C++

    The overloading assignment operator can be used to create an object just like the copy constructor. If a new object does not have to be created before the copying occurs, the assignment operator is used, and if the object is created then the copy constructor will come into the picture. Below is a program to explain how the assignment operator ...

  18. 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: class ...

  19. Assignment Operator Overload in c++

    An overloaded assignment operator should look like this: Complex &Complex::operator=(const Complex& rhs) {. real = rhs.real; imaginary = rhs.imaginary; return *this; }; You should also note, that if you overload the assignment operator you should overload the copy constructor for Complex in the same manner:

  20. Introduction to Python Operators

    Normally, these operators work with basic data types like numbers, but with operator overloading, you can define what they do when applied to your objects. Customizing Operators: You can change how operators like +, -, and == behave when used with your objects by defining special methods in your class.

  21. Announcing the Proxy 3 Library for Dynamic Polymorphism

    pro::operator_dispatch<"<<", true>: Specifies a dispatch for operator << expressions where the primary operand (proxy) is on the right-hand side (specified by the second template parameter true). Note that polymorphism in the "Proxy" library is defined by expressions rather than member functions, which is different from C++ virtual ...

  22. What are the basic rules and idioms for operator overloading?

    The bitwise shift operators << and >>, although still used in hardware interfacing for the bit-manipulation functions they inherit from C, have become more prevalent as overloaded stream input and output operators in most applications.. The stream operators, among the most commonly overloaded operators, are binary infix operators for which the syntax does not specify any restriction on whether ...

  23. Types of Operator Overloading in C++

    Assignment operator overloading is binary operator overloading.Overloading assignment operator in C++ copies all values of one. 4 min read. deque::operator= and deque::operator[] in C++ STL. Deque or Double ended queues are sequence containers with the feature of expansion and contraction on both the ends. They are similar to vectors, but are ...

  24. Is there a workaround for overloading the assignment operator in C#

    Unlike C++, in C# you can't overload the assignment operator. I'm doing a custom Number class for arithmetic operations with very large numbers and I want it to have the look-and-feel of the built-in numerical types like int, decimal, etc. I've overloaded the arithmetic operators, but the assignment remains... Here's an example: