/ | ||||
(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) |
Customizes the C++ operators for operands of user-defined types.
Syntax Overloaded operators Static overloaded operators Restrictions Canonical implementations Assignment operator Stream extraction and insertion Function call operator Increment and decrement Binary arithmetic operators Comparison operators Array subscript operator Bitwise arithmetic operators Boolean negation operator Rarely overloaded operators Notes Keywords Example Defect reports See also External links |
Overloaded operators are functions with special function names:
op | (1) | ||||||||
type | (2) | ||||||||
| (3) | ||||||||
| (4) | ||||||||
suffix-identifier | (5) | (since C++11) | |||||||
(6) | (since C++20) | ||||||||
op | - | any of the following operators:+ - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= << >> >>= <<= == != <= >= <=>(since C++20) && || ++ -- , ->* -> ( ) [ ] |
When an operator appears in an expression , and at least one of its operands has a class type or an enumeration type , then overload resolution is used to determine the user-defined function to be called among all the functions whose signatures match the following:
Expression | As member function | As non-member function | Example |
---|---|---|---|
@a | (a).operator@ ( ) | operator@ (a) | ! calls .operator!() |
a@b | (a).operator@ (b) | operator@ (a, b) | << 42 calls .operator<<(42) |
a=b | (a).operator= (b) | cannot be non-member | Given s;, s = "abc"; calls s.operator=("abc") |
a(b...) | (a).operator()(b...) | cannot be non-member | Given r;, auto n = r(); calls r.operator()() |
a[b...] | (a).operator[](b...) | cannot be non-member | Given <int, int> m;, m[1] = 2; calls m.operator[](1) |
a-> | (a).operator-> ( ) | cannot be non-member | Given <S> p;, p->bar() calls p.operator->() |
a@ | (a).operator@ (0) | operator@ (a, 0) | Given <int>::iterator i;, i++ calls i.operator++(0) |
In this table, is a placeholder representing all matching operators: all prefix operators in @a, all postfix operators other than -> in a@, all infix operators other than = in a@b. |
In addition, for comparison operators ==, !=, <, >, <=, >=, <=>, overload resolution also considers the generated from operator== or operator<=>. | (since C++20) |
Note: for overloading co_await , (since C++20) user-defined conversion functions , user-defined literals , allocation and deallocation see their respective articles.
Overloaded operators (but not the built-in operators) can be called using function notation:
Overloaded operators that are member functions can be declared . However, this is only allowed for operator() and operator[]. Such operators can be called using function notation. However, when these operators appear in expressions, they still require an object of class type. SwapThem { template <typename T> static void operator()(T& lhs, T& rhs) { std:: (lhs, rhs); } template <typename T> static void operator[](T& lhs, T& rhs) { std:: (lhs, rhs); } }; inline constexpr SwapThem swap_them {}; void foo() { int a = 1, b = 2; swap_them(a, b); // OK swap_them[a, b]; // OK SwapThem{}(a, b); // OK SwapThem{}[a, b]; // OK SwapThem::operator()(a, b); // OK SwapThem::operator[](a, b); // OK SwapThem(a, b); // error, invalid construction SwapThem[a, b]; // error } | (since C++23) |
, , and (comma) lose their special when overloaded and behave like regular function calls even when they are used without function-call notation. | (until C++17) |
Besides the restrictions above, the language puts no other constraints on what the overloaded operators do, or on the return type (it does not participate in overload resolution), but in general, overloaded operators are expected to behave as similar as possible to the built-in operators: operator + is expected to add, rather than multiply its arguments, operator = is expected to assign, etc. The related operators are expected to behave similarly ( operator + and operator + = do the same addition-like operation). The return types are limited by the expressions in which the operator is expected to be used: for example, assignment operators return by reference to make it possible to write a = b = c = d , because the built-in operators allow that.
Commonly overloaded operators have the following typical, canonical forms: [1]
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:
The canonical move assignment is expected to (that is, a state with class invariants intact), and either or at least leave the object in a valid state on self-assignment, and return the lhs by reference to non-const, and be noexcept: T& operator=(T&& other) noexcept { // Guard self assignment if (this == &other) return *this; // delete[]/size=0 would also be ok delete[] mArray; // release resource in *this mArray = (other.mArray, nullptr); // leave other in valid state size = (other.size, 0); return *this; } | (since C++11) |
In those situations where copy assignment cannot benefit from resource reuse (it does not manage a heap-allocated array and does not have a (possibly transitive) member that does, such as a member std::vector or std::string ), there is a popular convenient shorthand: the copy-and-swap assignment operator, which takes its parameter by value (thus working as both copy- and move-assignment depending on the value category of the argument), swaps with the parameter, and lets the destructor clean it up.
This form automatically provides strong exception guarantee , but prohibits resource reuse.
The overloads of operator>> and operator<< that take a std:: istream & or std:: ostream & as the left hand argument are known as insertion and extraction operators. Since they take the user-defined type as the right argument ( b in a @ b ), they must be implemented as non-members.
These operators are sometimes implemented as friend functions .
When a user-defined class overloads the function call operator, operator ( ) , it becomes a FunctionObject type.
An object of such a type can be used in a function call expression:
Many standard algorithms, from std:: sort to std:: accumulate accept FunctionObject s to customize behavior. There are no particularly notable canonical forms of operator ( ) , but to illustrate the usage:
When the postfix increment or decrement operator appears in an expression, the corresponding user-defined function ( operator ++ or operator -- ) is called with an integer argument 0 . Typically, it is implemented as T operator ++ ( int ) or T operator -- ( int ) , where the argument is ignored. The postfix increment and decrement operators are usually implemented in terms of the prefix versions:
Although the canonical implementations of the prefix increment and decrement operators return by reference, as with any operator overload, the return type is user-defined; for example the overloads of these operators for std::atomic return by value.
Binary operators are typically implemented as non-members to maintain symmetry (for example, when adding a complex number and an integer, if operator+ is a member function of the complex type, then only complex + integer would compile, and not integer + complex ). Since for every binary arithmetic operator there exists a corresponding compound assignment operator, canonical forms of binary operators are implemented in terms of their compound assignments:
Standard algorithms such as std:: sort and containers such as std:: set expect operator < to be defined, by default, for the user-provided types, and expect it to implement strict weak ordering (thus satisfying the Compare requirements). An idiomatic way to implement strict weak ordering for a structure is to use lexicographical comparison provided by std::tie :
Typically, once operator < is provided, the other relational operators are implemented in terms of operator < .
Likewise, the inequality operator is typically implemented in terms of operator == :
When three-way comparison (such as std::memcmp or std::string::compare ) is provided, all six two-way comparison operators may be expressed through that:
The inequality operator is automatically generated by the compiler if operator== is defined. Likewise, the four relational operators are automatically generated by the compiler if the three-way comparison operator operator<=> is defined. operator== and operator!=, in turn, are generated by the compiler if operator<=> is defined as defaulted: Record { name; unsigned int floor; double weight; auto operator<=>(const Record&) const = default; }; // records can now be compared with ==, !=, <, <=, >, and >=See for details. | (since C++20) |
User-defined classes that provide array-like access that allows both reading and writing typically define two overloads for operator [ ] : const and non-const variants:
Alternatively, they can be expressed as a single member function template using an : T { decltype(auto) operator[](this auto& self, idx) { return self.mVector[idx]; } }; | (since C++23) |
If the value type is known to be a scalar type, the const variant should return by value.
Where direct access to the elements of the container is not wanted or not possible or distinguishing between lvalue c [ i ] = v ; and rvalue v = c [ i ] ; usage, operator [ ] may return a proxy. See for example std::bitset::operator[] .
operator[] can only take one subscript. In order to provide multidimensional array access semantics, e.g. to implement a 3D array access a[i][j][k] = x;, operator[] has to return a reference to a 2D plane, which has to have its own operator[] which returns a reference to a 1D row, which has to have operator[] which returns a reference to the element. To avoid this complexity, some libraries opt for overloading operator() instead, so that 3D access expressions have the Fortran-like syntax a(i, j, k) = x;. | (until C++23) |
operator[] can take any number of subscripts. For example, an operator[] of a 3D array class declared as T& operator[]( x, y, z); can directly access the elements. #include <cassert> #include <iostream> template<typename T, Z, Y, X> struct Array3d { <T, X * Y * Z> m{}; constexpr T& operator[]( z, y, x) // C++23 { (x < X and y < Y and z < Z); return m[z * Y * X + y * X + x]; } }; int main() { Array3d<int, 4, 3, 2> v; v[3, 2, 1] = 42; << "v[3, 2, 1] = " << v[3, 2, 1] << '\n'; }Output: | (since C++23) |
User-defined classes and enumerations that implement the requirements of BitmaskType are required to overload the bitwise arithmetic operators operator & , operator | , operator ^ , operator~ , operator & = , operator | = , and operator ^ = , and may optionally overload the shift operators operator << operator >> , operator >>= , and operator <<= . The canonical implementations usually follow the pattern for binary arithmetic operators described above.
The operator operator! is commonly overloaded by the user-defined classes that are intended to be used in boolean contexts. Such classes also provide a user-defined conversion function to boolean type (see for the standard library example), and the expected behavior of operator! is to return the value opposite of operator bool. | (until C++11) |
Since the built-in operator ! performs , user-defined classes that are intended to be used in boolean contexts could provide only operator bool and need not overload operator!. | (since C++11) |
The following operators are rarely overloaded:
macro | Value | Std | Feature |
---|---|---|---|
202207L | (C++23) | static operator() | |
202211L | (C++23) | static operator[] |
[ edit ] example, [ edit ] defect reports.
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
C++98 | the non-member prefix increment operator could only have a parameter of class or enumeration type | no type requirement |
Common operators | ||||||
---|---|---|---|---|---|---|
a = b | ++a | +a | !a | a == b | a[...] | function call |
a(...) | ||||||
comma | ||||||
a, b | ||||||
conditional | ||||||
a ? b : c | ||||||
Special operators | ||||||
converts one type to another related type |
on StackOverflow C++ FAQ |
IMAGES
VIDEO
COMMENTS
Derived& operator=(const Base& a); in your Derived class. A default assignment operator, however, is created: Derived& operator=(const Derived& a); and this calls the assignment operator from Base. So it's not a matter of inheriting the assignment operator, but calling it via the default generated operator in your derived class.
The copy assignment operator of the derived class that is implicitly declared by the compiler hides assignment operators of the base class. Use using declaration in the derived class the following way. using A::operator =; B():A(){}; virtual ~B(){}; virtual void doneit(){myWrite();} Another approach is to redeclare the virtual assignment ...
In C++, like other functions, assignment operator function is inherited in derived class. For example, in the following program, base class assignment operator function can be accessed using the derived class object. Output: base class assignment operator called. Summer-time is here and so is the time to skill-up!
Derived classes. Any class type (whether declared with class-keyclass or struct) may be declared as derived from one or more base classes which, in turn, may be derived from their own base classes, forming an inheritance hierarchy.
Assignment performs implicit conversion from the value of rhs to the type of lhs and then replaces the value in the object designated by lhs with the converted value of rhs. Assignment also returns the same value as what was stored in lhs (so that expressions such as a = b = c are possible). The value category of the assignment operator is non ...
If a using-declaration brings the base class assignment operator into derived class, whose signature happens to match the derived class's copy-assignment or move-assignment operator, that operator is hidden by the implicitly-declared copy/move assignment operator of the derived class.
If you define your own assignment operators, the compiler will not automatically call your base class's assignment operators for you. Unless your base class's assignment operators themselves are broken, you should call them explicitly from your derived class's assignment operators (again, assuming you create them in the first place).
In C++, it is possible to inherit attributes and methods from one class to another. We group the "inheritance concept" into two categories: derived class (child) - the class that inherits from another class. base class (parent) - the class being inherited from. To inherit from a class, use the : symbol.
Assignment operators are used in programming to assign values to variables. We use an assignment operator to store and update data within a program. They enable programmers to store data in variables and manipulate that data. The most common assignment operator is the equals sign (=), which assigns the value on the right side of the operator to ...
The capability of a class to derive properties and characteristics from another class is called Inheritance. Inheritance is one of the most important features of Object Oriented Programming in C++. In this article, we will learn about inheritance in C++, its modes and types along with the information about how it affects different properties of the class.
the copy assignment operator selected for every non-static class type (or array of class type) member of T is trivial. A trivial copy assignment operator makes a copy of the object representation as if by std::memmove. All data types compatible with the C language (POD types) are trivially copy-assignable.
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.
The first is quite straightforward: You simply create objects of your existing class inside the new class. This is called composition because the new class is composed of objects of existing classes. The second approach is subtler. You create a new class as a type of an existing class. You literally take the form of the existing class and add ...
5,6) Definition of a move assignment operator outside of class definition (the class must contain a declaration (1)). 6) The move assignment operator is explicitly-defaulted. The move assignment operator is called whenever it is selected by overload resolution, e.g. when an object appears on the left-hand side of an assignment expression, where ...
Understanding Inheritance, const Assignment Operator, and C++: A Closer Look Inheritance is a fundamental concept in object-oriented programming, allowing the creation of new classes that reuse, extend, and modify the behavior defined in other classes. In C++, inheritance is implemented using the : keyword. When a class inherits from another class, it automatically gains access to all the ...
Move assignment 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 move assignment operator. (since C++11)
C++ Class Inheritance and assignment operator Asked 11 years, 1 month ago Modified 4 years, 9 months ago Viewed 377 times
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.
It is not possible to change the precedence, grouping, or number of operands of operators. The overload of operator -> must either return a raw pointer, or return an object (by reference or by value) for which operator -> is in turn overloaded. The overloads of operators && and || lose short-circuit evaluation.