Skip to content

Commit 0cdff54

Browse files
committed
Add C++ rule of five and object management rules
1 parent d2b37ff commit 0cdff54

File tree

2 files changed

+159
-0
lines changed

2 files changed

+159
-0
lines changed

C++/03 C++ - Object-Oriented Syntax.md

+159
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ I'll be adapting it from the ever amazing Derek Banas: https://www.youtube.com/w
3131
2.4 [Child Class Declaration](#2.4)
3232
2.5 [Virtual Methods and Polymorphisms](#2.5)
3333
2.6 [Friendship](#2.6)
34+
2.7 [Operator Overloading](#2.7)
35+
2.8 [Rules for Object Management](#2.8)
3436

3537

3638

@@ -605,6 +607,163 @@ int friendly_dragon_happiness_detector(const Dragon& dragon){
605607
606608
607609
610+
### 2.7 Operator Overloading <a name="2.7"></a>
611+
612+
[go to top](#top)
613+
614+
You can redefine what an operator does to a class!
615+
616+
So you can change what the `+` operator does, for example.
617+
618+
All you need to do, is use the `operator` keyword, followed by the operator that you want to redefine. (Do this inside a class, of course.)
619+
620+
```c++
621+
public:
622+
MyClass operator + (MyClass const &MyClassObj)
623+
{
624+
// Do some stuff
625+
return something;
626+
}
627+
```
628+
629+
You can also overload conversion operators!
630+
631+
```c++
632+
class Wow
633+
{
634+
public:
635+
Wow() {} // Some contructor
636+
637+
operator float()
638+
{
639+
// Do some float calculation stuff
640+
return float_conversion_result;
641+
}
642+
}
643+
644+
// Our new overloaded float conversion operator will be usable like so!
645+
a = Wow();
646+
float b = a; // Wow!
647+
```
648+
649+
**Example**
650+
651+
```c++
652+
// Source: https://www.geeksforgeeks.org/operator-overloading-c/
653+
654+
#include<iostream>
655+
using namespace std;
656+
657+
class Complex {
658+
private:
659+
int real, imag;
660+
public:
661+
Complex(int r = 0, int i =0) {real = r; imag = i;}
662+
663+
// This is automatically called when '+' is used with
664+
// between two Complex objects
665+
Complex operator + (Complex const &obj) {
666+
Complex res;
667+
res.real = real + obj.real;
668+
res.imag = imag + obj.imag;
669+
return res;
670+
}
671+
void print() { cout << real << " + i" << imag << endl; }
672+
};
673+
674+
int main()
675+
{
676+
Complex c1(10, 5), c2(2, 4);
677+
Complex c3 = c1 + c2; // An example call to "operator+"
678+
c3.print();
679+
}
680+
```
681+
682+
#### **Caveats**
683+
684+
Almost every operator can be overloaded, except for...
685+
686+
- `.`
687+
- `::`
688+
- `?:`
689+
- `sizeof`
690+
691+
[Reasons being...](<http://www.stroustrup.com/bs_faq2.html#overload-dot>)
692+
693+
694+
695+
### 2.8 Rules for Object Management <a name="2.8"></a>
696+
697+
[go to top](#top)
698+
699+
#### **Introduction**
700+
701+
C++ provides 6 special functions that are called default operations that deal with managing an object's lifecycle.
702+
703+
| Operation | Signature |
704+
| :-----------------: | :-------------------: |
705+
| Default constructor | `X()` |
706+
| Copy constructor | `X(const X&)` |
707+
| Copy assignment | `operator=(const X&)` |
708+
| Move constructor | `X(X&&)` |
709+
| Move assignment | `operator=(X&&)` |
710+
| Destructor | `~X()` |
711+
712+
You can explicitly define them, delete them, or lean on the compiler's default.
713+
714+
```c++
715+
X() {}; // Default constructor, explicitly defined
716+
X() = default; // Default constructor, defaulting to compiler implementation
717+
X() = delete; // Explicitly deleted default constructor. There will be no implementation
718+
```
719+
720+
The rules for object management help to keep your programs running as expected. You can treat the rules like boilerplate, but just keep them in mind.
721+
722+
723+
724+
#### **Rule of Zero**
725+
726+
This one is fairly simple. Since it keeps things simple.
727+
728+
> **If you can avoid redefining any default operations, do.**
729+
730+
731+
732+
#### **Rule of Three**
733+
734+
> **If you redefine at least one of the following operations: Destructor, Copy Constructor, Copy Assignment, explicitly redefine all three.**
735+
736+
Example:
737+
738+
- Suppose we have a class with a redefined destructor `~X()`
739+
- When the default copy assignment `operator=(const X&)` or copy constructor `X(const X&)` is used, it copies all class members, including the redefined destructor, and **any declared local pointers without reallocating extra memory for those copied local pointers**.
740+
- In other words, using the default copy assignment and copy constructor operations, all pointers local to each class instance point to the same piece of memory!
741+
- So when the program goes out of scope, for the same destructor is called for all copies of the object, the same address pointed to by all pointers in instances of the class are deleted multiple times, crashing the program.
742+
743+
Similar logic can be used for the other two operations. If you only define one copy operation, the other gets used as the default and will really mess up your memory management.
744+
745+
746+
747+
#### **Rule of Five**
748+
749+
Actually all six operations are intimately linked. So the rule of five (it's the rule of six if you count the default constructor) exists to remind you that...
750+
751+
> **If you redefine or =delete any default operation, define or =delete them all.**
752+
753+
If you don't follow the rule, your objects might behave weirdly.
754+
755+
Furthermore, when you actually define them, make sure you use **consistent semantics**. (Example: If you use shallow copies (copying of pointers) in a single copy operation, do not use deep copies (copying pointers and pointed data) for the other copy operator))
756+
757+
(You'll generally want to use deep copies usually anyway...)
758+
759+
```c++
760+
// Shallow copy
761+
p = a.p;
762+
763+
// Deep copy
764+
p= new int(*(a.p))
765+
```
766+
608767
609768
610769
```
76.8 KB
Loading

0 commit comments

Comments
 (0)