"To overload an operator, the syntax is just the keyword **operator** followed by the operator to overload. In the following we will just replace the `Add` method by `operator+`.\n",
"\n",
"The following code illustrate how to do so... but unfortunately doesn't run with Xeus Cling (you may play with it [@Coliru](https://coliru.stacked-crooked.com/a/765b9dc1e2b73c71)).\n"
"The following code illustrate how to do so:\n"
]
},
{
...
...
@@ -145,7 +145,8 @@
"metadata": {},
"outputs": [],
"source": [
"// DOESN'T RUN WITH XEUS-CLING\n",
"%%cpptoolbox cppyy/cppdef\n",
"// < We need to help the kernel interpret properly the code below, which is perfectly valid C++. Don't bother about this magics!\n",
"If you want it to be possible, you have to define the operator with arguments in both orders; you therefore need to use out-of-class prototype of the function (can't show it currently due to Xeus-cling limitation, available [@Coliru](https://coliru.stacked-crooked.com/a/c03fc40e0f0a8ea0)).\n",
"If you want it to be possible, you have to define the operator with arguments in both orders; you therefore need to use out-of-class prototype of the function.\n",
"\n",
"Of course, it is a **good practice** to define one in way of the other:"
"Of course, it is a **good practice** in this case to define one in way of the other:"
"// Won't run in Xeus-cling, as it's not within the class declaration\n",
"// Won't run in the notebook, as it's not declared within the class declaration\n",
"\n",
"explicit operator int() const;\n",
"explicit operator double() const;"
...
...
%% Cell type:markdown id: tags:
# [Getting started in C++](./) - [Operators](./0-main.ipynb) - [Introduction](./1-Intro.ipynb)
%% Cell type:markdown id: tags:
## Motivation
We've seen at length in the object programming part that classes are basically new types defined by the developer. However sometimes we would like to use exactly the same syntax as for the base type. Let's see for instance a basic class to handle tri-dimensional vectors:
%% Cell type:code id: tags:
``` c++
classVector
{
// Friendship because `Add()` needs to access private members and no accessors were defined.
Now the same with a _plain old data type_ is much more natural to write with no (apparent) method:
%% Cell type:code id: tags:
``` c++
{
doublex1=3.;
doublex2=7.;
doublex3=x1+x2;
std::cout<<x3<<std::endl;
}
```
%% Cell type:markdown id: tags:
C++ provides the way to mimic this behaviour with **operator overloading**. This is a very powerful conceit, but also one that should be approached with some care...
We will see the general way to define such an operator in this notebook and see in dedicated notebooks which are the ones specifically useful.
## Overloading an operator
To overload an operator, the syntax is just the keyword **operator** followed by the operator to overload. In the following we will just replace the `Add` method by `operator+`.
The following code illustrate how to do so... but unfortunately doesn't run with Xeus Cling (you may play with it [@Coliru](https://coliru.stacked-crooked.com/a/765b9dc1e2b73c71)).
The following code illustrate how to do so:
%% Cell type:code id: tags:
``` c++
// DOESN'T RUN WITH XEUS-CLING
%%cpptoolboxcppyy/cppdef
// < We need to help the kernel interpret properly the code below, which is perfectly valid C++. Don't bother about this magics!
#include<iostream>
classVectorPlus
{
public:
VectorPlus(doublex,doubley,doublez);
VectorPlus()=default;
voidPrint()const;
// Friendship as free function operator+ wouldn't otherwise be allowed to access data attributes.
VectorPlusAsMethodv4=v1.operator+(v2);// but "usual" method syntax is possible as well
v4.Print();
}
```
%% Cell type:markdown id: tags:
We see here in the definition of the `operator+` that both `VectorPlusAsMethod` objects added aren't symmetric: one is the data attribute while the other is the data attribute of another object given as an argument. If is often advised to rather use the free function version to avoid this asymmetry, but it is mostly a matter of taste as both are working.
As a side note, please remark the `VectorPlusAsMethod::operator+` implementation is able to reach the private data attributes of the argument `v`; this means the private status is set **at class level** and not at object level.
%% Cell type:markdown id: tags:
## Operator between different types
It is also possible to define an operator which acts upon two objects of different nature:
%% Cell type:code id: tags:
``` c++
%%cpptoolboxcppyy/cppdef
classVectorPlusDouble
{
public:
VectorPlusDouble(doublex,doubley,doublez);
VectorPlusDouble()=default;
voidPrint()const;
// Defined in the class declaration due to Xeus-cling limitation.
If you want it to be possible, you have to define the operator with arguments in both orders; you therefore need to use out-of-class prototype of the function (can't show it currently due to Xeus-cling limitation, available [@Coliru](https://coliru.stacked-crooked.com/a/c03fc40e0f0a8ea0)).
If you want it to be possible, you have to define the operator with arguments in both orders; you therefore need to use out-of-class prototype of the function.
Of course, it is a **good practice** to define one in way of the other:
Of course, it is a **good practice**in this case to define one in way of the other:
* The [precedence rules](https://en.cppreference.com/w/cpp/language/operator_precedence)(between`+` and `*` for instance)
You can't _invent_ new operators, but only redefine operators in the following list (taken from [Operators in C and C++](https://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B), please consult for more details):
* Other operators: `() , "" new new[] delete delete[]`
* Conversion operators - see next section
That list might be incomplete: `""` operator was introduced in C++ 11 (cf. [this blog post](https://www.fluentcpp.com/2016/12/08/strong-types-for-strong-interfaces/)), and `<=>` operator was introduced in C++ 20, for instance.
If not defined, some of them exist by default:
```
=
-> ->*
new delete
```
Some can never be redefined:
```
: :: . .* ? ?: sizeof
```
## Conversion operators
A conversion operator is a method of transforming an object into a given type. When the compiler needs to force the type of an object, implicitly or explicitly, it is this operator that will be called. A conversion operator is required for each type of conversion.