# Chapter 12 - Notes

In addition to encapsulating data in the form of member variables, and pieces of logic in the form of member functions, classes can also encapsulate **operators** that make it easy to operate on instances of a class.

### C++ Operators

Operators in C++ are the symbols that you use to manipulate one or more variables. The ones you are familiar with are the `+` and `-` operators.&#x20;

### Declaring Operators

Operators in C++ are not too different to that of a function, the only difference is the use of the `operator` keyword.&#x20;

The declaration of an operator is similar to that of a function declaration:

```cpp
return_type operator operator_symbol( ... parameters...);
```

The `operator_symbol` in this case could be any of the operator types available.&#x20;

### When to Overload Operators&#x20;

Operators are intuitive and easy to use. Consider a utility class `Date` that encapsulates the day, month, and year:&#x20;

```cpp
Date holiday (12, 25, 2016); // initialized to Dec 25, 2016
```

If you want to add a day to the `holiday` variable such that it should then contain Dec 26, 2016, it would be far more intuitive to be able to do:&#x20;

```cpp
holiday++;
```

As opposed to&#x20;

```cpp
holiday.Increment();
```

Likewise implementing the operator `<` would allow us to compare two instances of `Date`:

```cpp
if (date1 < date2) {
    // ...
} else {
    // ...
}
```

## Types of Operators&#x20;

Operators in C++ can be classified into two types, **unary operators** and **binary operators**.

## Unary Operators&#x20;

Unary operators are operators that function on a single operand.&#x20;

A unary operator can be either declared&#x20;

* in the global namespace&#x20;
* as a static member function&#x20;

```cpp
return_type operator operator_type (parameter_type);
```

* as a non-static member function

```cpp
return_type operator operator_type ();
```

It is similar to the above, but without the parameter, because the parameter that is being operation on is the instance of the class itself, referred to by the `this` pointer.&#x20;

### Types of Unary Operators&#x20;

| Operator               | Name                                   |
| ---------------------- | -------------------------------------- |
| `++`                   | Increment                              |
| `--`                   | Decrement                              |
| `*`                    | Pointer dereference                    |
| `->`                   | Member selection                       |
| `!`                    | Logical NOT                            |
| `&`                    | Address-of                             |
| `~`                    | One's complement                       |
| `+`                    | Unary plus                             |
| `-`                    | Unary negation                         |
| `Convertion operators` | **Implicit** conversion to other types |

### Example - Programming a Unary Increment / Decrement Operator&#x20;

{% hint style="info" %}
**Why does the postfix increment/decrement operator have an `int` parameter?**&#x20;

Is it purely to distinguish between the prefix and postfix operators.&#x20;

> &#x20;These explanations are needed because the mechanism is unique, and therefore a bit of a wart. Given a choice I would probably have introduced the `prefix` and `postfix` keywords, but that didn't appear feasible at the time.
> {% endhint %}

### Conversion Operators&#x20;

Consider the below usage of the `Date` class declared above:

```cpp
std::cout << holiday << std::endl;
```

Compiling the above code would yield a bunch of compiler errors that look like the following:&#x20;

```
note: candidate function template not viable: no known conversion from 
'Date' to 'char' for 2nd argument
```

The above error indicates that the compiler is trying to convert the type that we provided, `Date`, to a `char`, which is a type that `std::cout` accepts.&#x20;

We receive multiple of these lines, each of which is an attempt by the compiler to convert `Date` into another type that is accepted by `std::cout`.&#x20;

Eventually it finds that it is not able to convert `Date` into any possible type, and returns to us a compiler error.&#x20;

We know that `std::cout` can accept and print a `const char*` type:&#x20;

```cpp
std::cout << "Hello world!\n";  // const char* works!
```

So getting `std::cout` to work with an instance of `Date` is simply adding an operator that can implicitly convert a `Date`  to a `const char*`:&#x20;

```cpp
operator const char*() {
    // ... 
}
```

Now the instance of `Date` can be used with `std::cout`, taking advantage of the fact that `std::cout` can accept `const char*` types. The compiler will try to find a suitable conversion operator that returns a type that can be used with `std::cout`, and **implicitly** invokes it for you. &#x20;

#### Explicit Conversion&#x20;

To avoid implicit conversions, use the keyword `explicit` at the start of the operator declaration:

```cpp
explicit operator const char*() {
    // ...
}
```

This forces the programmer to assert the intention to convert using a cast:

```cpp
std::cout << static_cast<const char*>(holiday) << std::endl;
```

### Example - Programming Dereference Operator (\*) and Member Selection Operator (->)

{% hint style="info" %}
The secret of `std::unique_ptr` is that it implements `operator*` and `operator->` to do clever things.&#x20;
{% endhint %}

## Binary Operators&#x20;

Binary operators are operators that function on **two operands**.

A binary operator can be declared as

* a global function&#x20;
* a static member function

```cpp
return_type operator operator_type (parameter1, parameter2);
```

* a class member function

```cpp
return_type operator operator_type (parameter);
```

The reason the class member function version only accepts one parameter is that the second parameter is the instance of the class itself, accessed through the `this` pointer.&#x20;

### Types of Binary Operators&#x20;

| Operator | Name                                           |
| -------- | ---------------------------------------------- |
| `,`      | Comma                                          |
| `!=`     | Inequality                                     |
| `%`      | Modulus                                        |
| `%=`     | Modulus assignment                             |
| `&`      | Bitwise AND                                    |
| `&&`     | Logical AND                                    |
| `&=`     | Bitwise AND assignment                         |
| `*`      | Multiplication                                 |
| `*=`     | Multiplication assignment                      |
| `+`      | Addition                                       |
| `+=`     | Addition assignment                            |
| `-`      | Subtraction                                    |
| `-=`     | Subtraction assignment                         |
| `->*`    | Pointer-to-member selection                    |
| `/`      | Division                                       |
| `/=`     | Division assignment                            |
| `<`      | Less than                                      |
| `<<`     | Left shift                                     |
| `<<=`    | Left shift assignment                          |
| `<=`     | Less than or equal to                          |
| `=`      | Assignment / copy assignment / move assignment |
| `==`     | Equal to                                       |
| `>`      | Greater than                                   |
| `>=`     | Greater than or equal to                       |
| `>>`     | Right shift                                    |
| `>>=`    | Right shift assignment                         |
| `^`      | Exclusive OR                                   |
| `^=`     | Exclusive OR assignment                        |
| `\|`     | Bitwise inclusive OR                           |
| `\|=`    | Bitwise inclusive OR assignment                |
| `\|\|`   | Logical OR                                     |
| `[]`     | Subscript operator                             |

### Example - Programming Binary Addition and Subtraction Operators

### Example - Programming Addition Assignment and Subtraction Assignment Operators&#x20;

### Example - Programming Equality and Inequality Operators&#x20;

In the absence of an equality operator `==`, the compiler simply performs a binary comparison of the two objects and returns `true` when they are exactly identical.&#x20;

This binary comparison will work for instances of classes containing simple data types like the `Date` class, but it will not work if the class in question has a non-static string member such as `char*`.&#x20;

When two instances of such classes are compared, a binary comparison of the member attributes would compare the pointer values of the `char*` member variables. These would not be equal even if the values the pointers point to are equal, and would therefore return `false` consistently.&#x20;

This problem can be solved by defining comparison operators.&#x20;

```cpp
bool operator==(const ClassType& other) {
    // ...
}

bool operator!=(const ClassType& other) {
    // ...
}
```

**(Bonus: The other comparison operators - `<`, `>`, `<=`, and `>=` are implemented the same way; have a go at implementing them)**

### Subscript Operator&#x20;

The subscript operator is one that allows an array-style (`[]`) access to a class. The syntax for a subscript operator is:

```cpp
return_type& operator[](subscript_type& index);
```

Using the `VectorInt` class from Question 1 of Worked Exercises 1 as an example, a subscript operator would make it really easy to access individual elements.

```cpp
class VectorInt {
    int* values;
    
    // ...
public:
    int& operator[](int index) {
        return values[index];
    }
};

int main() {
    auto ints = VectorInt();
    // add some elements to it 
    for (int i = 0; i < ints.size(); i++) {
        std::cout << ints[i] << std::endl;
    }
}
```

The subscript operator now helps us iterate through the contents contained in a `VectorInt` object using normal array semantics.&#x20;

Because the value returned is a reference, we can also modify the values returned, and it will be reflected in the `VectorInt` object.&#x20;

{% hint style="info" %}
The `const` keyword can change the behaviour of the subscript operator. For example, returning a `const` reference:

```cpp
const int& operator[](int index);
```

You prevent one from modifying the values directly via `operator[]`.

Likewise defining the function as `const` denotes that it actually does not modify any member attributes:

```cpp
const int& operator[](int index) const;
```

Furthermore, you are allowed to define both subscript operators, and the compiler will invoke the `const` function for reading, and the non-`const` version for writing.
{% endhint %}

## Function Operator&#x20;

The `operator()` makes objects behave like a function. Their usage can include parameters, giving them the name **unary** or **binary** **predicates**, depending on the number of operands they work on.&#x20;

Objects who implement an `operator()` overload are also called **function objects** or **functors** (portmanteau of 'function pointers').

## Move Constructor & Move Assignment Operator&#x20;

Move constructors and move assignment operators are performance optimisation features implemented as part of the C++11 standard.

These are similar to the **copy constructor** and **copy assignment operator**, except temporary values (*rvalues* that don't exist beyond the statement) are not wastefully copied.&#x20;

This is especially useful for handling classes with dynamically allocated resources, such as a dynamic array or string class.&#x20;

### Motivation&#x20;

{% hint style="warning" %}
This section needs updating for C++17
{% endhint %}
