# Chapter 9 - Notes

## Classes

Classes are abstract objects that share common:

* attributes
* behaviour (methods)&#x20;

### Declaring a class&#x20;

```cpp
struct Human {
    // Attributes, or member variables
    std::string name;
    std::string gender;
    int netWorth;
    
    // Member functions or member methods 
    void introduceSelf();
    void addNetWorth(int amount);
};
```

Classes provide a way to create our own **data types**, which allows us to **encapsulate data** within attributes which can change the behaviour of the corresponding objects.&#x20;

**Encapsulation** is the ability to logically group data and functions together.&#x20;

## Objects and Instances&#x20;

Classes are simply abstract objects, like `Human`, `Country`, or `Sport`. Declaring a class has no effect on the execution of a program.&#x20;

These classes are simply blueprints for which we can construct one or more **instances** from. Using the `Sport` class as an example, we may create objects referring to the sports tennis, running, or golf. &#x20;

### Creating an instance&#x20;

```cpp
// Static declaration 
int number;
Human some_human;

// Dynamic declaration
int number_ptr = new int(5);
delete number_ptr;

Human* human_ptr = new Human();
delete human_ptr;
```

### Accessing members&#x20;

Consider the following class definition:

```cpp
struct Human {
    std::string name;
    int age;
    
    void introduceSelf() {
        std::cout << "Hi, my name is " << name 
                  << " and I am " << age 
                  << " years old" 
                  << std::endl;
    }
};
```

#### Using the Dot Operator&#x20;

Members of an instance may be accessed using the dot operator (`.`):

```cpp
Human some_human;

// Modifying member attributes
some_human.name = "Andrew";
some_human.age = 20;

// Accessing member attributes
std::cout << some_human.name << std::endl;
std::cout << some_human.age << std::endl;

// Calling member functions
some_human.introduceSelf();
```

#### Using the Pointer Operator&#x20;

Members of an **instance pointer** may be accessed using the pointer operator (`->`):

```cpp
Human* human_ptr = new Human;

// Modifying member attributes
(*human_ptr).name = "Andrew";
(*human_ptr).age = 20;

// Accessing member attributes 
std::cout << human_ptr->name << std::endl;
std::cout << human_ptr->age << std::endl;

// Calling member functions
human_ptr->introduceSelf();

delete human_ptr;
```

{% hint style="info" %}
The **attributes** for each class instance is specific only to each instance. That is to say that modifying the attributes for one instance will not affect the attributes of another.&#x20;
{% endhint %}

## Keywords 'public' and 'private'

Class members, both attributes and methods, can be classified as **private** or **public**.

* `public`: members that can be accessed and used by **anyone in possession of an instance** of the class&#x20;
* `private`: members that can only be used **within the class**&#x20;

```cpp
class Human {
private:
    // Everything within this block is private
    int age;
    string name;
    // Everything within this block is public 
public:
    int getAge() { 
        return age; 
    }
    
    void setAge(int newAge) {
        if (newAge > 0) {
            age = newAge;
        }
    }
};
```

```cpp
Human adam; 

std::cout << adam.age << std::endl;  // compile error 
std::cout << adam.getAge() << std::endl;  // OK
```

This prevents anyone from modifying the `name` and `age` attributes of an instance of `Human`.&#x20;

**Classes** have private members by default.&#x20;

**Structs** have public members by default.

## Constructors&#x20;

A constructor is the function invoked during the instantiation of a class.

### Declaring and Implementing a Constructor&#x20;

```cpp
class Human {
public:
    Human();  // Declaration
};
```

```cpp
class Human {
public:
    Human() {}  // Implementation 
};
```

This is admittedly not very useful, here's a useful version.

```cpp
class Human {
public:
    std::string name;
    int age;
    
    Human(std::string some_name, int some_age) {
        name = some_name;
        age = some_age;
    }
};
```

Which allows us to construct instances in the following manner:

```cpp
Human some_human = Human("Andrew", 20);
```

### Overloading Constructors

Much like regular functions, constructors can also be overloaded&#x20;

```cpp
class Human {
private:
    std::string name;
    int age;

public:    
    Human() {
        name = "unknown";
        age = -1;
    }
    
    Human(int some_age) {
        name = "unknown";
        age = some_age;
    }
    
    Human(std::string some_name, int some_age) {
        name = some_name;
        age = some_age;
    }
};
```

Which allows us to construct instances in the following ways:

```cpp
Human zero;  // Constructor 1 
Human first = Human();  // Constructor 1
Human second = Human(20);  // Constructor 2
Human third = Human("Andrew", 20);  // Constructor 3 
```

### Constructor with Default Parameter Values&#x20;

Much like regular functions, constructor parameters can also be provided with a default value, as an alternative to overloading.

```cpp
class Human {
private:
    std::string name;
    int age;

public:       
    Human(std::string some_name = "unknown", int some_age = 0) {
        name = some_name;
        age = some_age;
    }
};
```

```cpp
Human alice = Human(); // Uses default name "unknown" and default age 0
Human bob = Human("Bob"); // Uses default age 0
Human charlie = Human("Charlie", 20);  // Doesn't use any defaults
```

### Constructor with Initialisation Lists

```cpp
class Human {
private:
    int age;
    string name;

public:
    Human(string some_name = "unknown", int humansAge = 0) 
          : name(some_name), age(some_age) {}
};
```

This is the same as the previous example, but will be useful for invoking base class constructors, which we will learn about later.&#x20;

## Destructors&#x20;

Destructors are functions that are called when an instance is destroyed. This will occur in two cases:

* When an statically created object goes out of scope
* When `delete` is called on a dynamically allocated object&#x20;

### Declaring and Implementing a Destructor&#x20;

The syntax for a destructor is very similar to that of a constructor, except prefixed with a tilde (`~`):

```cpp
struct Human {
    ~Human();  // Declaration 
}
```

```cpp
struct Human {
    ~Human() {};  // Implementation
}
```

### When to use a destructor&#x20;

Since the destructor is invoked when an object of a class is destroyed, it is the ideal place to reset any variables, or release any memory dynamically allocated during the lifetime of the object.&#x20;

```cpp
struct Human {
    int* age_ptr;
    
    Human() {
         // Each `Human` object dynamically allocates an integer
        age_ptr = new int(0); 
    }
    
    ~Human() {
        // Which should be cleaned up in the destructor
        delete age_ptr;
    }
}
```

## Copy Constructors

Arguments passed into a function like the below are copied:

```cpp
double foo(int a, int b); 
```

Arguments sent as parameters `a` and `b` are copied when `foo()` is invoked. This applies to objects or instances of classes as well.&#x20;

### Shallow copying and associated problems&#x20;

Classes such as `Human` in the previous example contain a member variable `age_ptr` that points to dynamically allocated memory. When an instance of this class is copied, the **pointer member is copied**, but not the underlying memory that it references, resulting in two objects pointing to the same dynamically allocated integer in memory.

When the first object is destructed, `delete` deallocates the memory in the destructor, therefore invalidating the pointer held by the original object. This will cause a double-free error when the original object is later destructed.&#x20;

Such copies are **shallow** and threaten the stability of the program.&#x20;

### Ensuring deep copies with the copy constructor&#x20;

Copy constructors are special constructors that are invoked every time an object of the class is copied.&#x20;

```cpp
struct Human {
    // ...
    Human(const Human& original); // copy constructor 
}
```

The copy constructor takes an object of the same class, by reference, as a parameter. This parameter will be the source object that you will be copying from.&#x20;

You would use the reference to this object to ensure a deep copy of all necessary in the source.&#x20;

```cpp
struct Human {
    int* age_ptr;
    Human() {
        age_ptr = new int(5);
    }
    
    Human(const Human& original) {
        if (original.age_ptr != nullptr) {
            age_ptr = new int;  // Create a new int ourselves
            *age_ptr = *(original.age_ptr);  // Copy the value
        }
    }
}
```

Using `const` in the copy constructor ensures that the copy constructor does not modify the source object that is being referred to.&#x20;

{% hint style="info" %}
The parameter in the copy constructor has to be passed by a reference, otherwise the copy constructor will invoke itself to copy the parameter, which will invoke itself again to copy the parameter, which will invoke itself again... you get the point.&#x20;
{% endhint %}

### Ensuring deep copies with the copy assignment constructor&#x20;

The copy constructor ensures deep copies in the case of pass-by-copy function calls, but does not fix copies via assignment:

```cpp
Human first;
Human second;
second = first; // `first` is copied into `second`!
// double-free happens when the program exits 
```

Therefore, we also need to implement the **copy assignment constructor**:

```cpp
struct Human {
    int* age_ptr;
    Human() {
        age_ptr = new int(5);
    }
    
    Human(const Human& original) {
        if (original.age_ptr != nullptr) {
            age_ptr = new int;  // Create a new int ourselves
            *age_ptr = *(original.age_ptr);  // Copy the value
        }
    }
    
    Human& operator=(const Human& original) {
        if (original.age_ptr != nullptr) {
            age_ptr = new int;  // Create a new int ourselves
            *age_ptr = *(original.age_ptr);  // Copy the value
        }
        return *this;
    }
}
```

## Move Constructors&#x20;

## Static Class Members and Functions

When the keyword `static` is used on a class' data member, it ensures that the member is shared across all instances.

When `static` is used on a local variable declared within the scope of a function, it ensures that the variable retains its value between function calls.

When `static` is used on a member function, the method is shared across all instances of the class. Additionally `static` class methods do not require an instance to be invoked.&#x20;

## Different Uses of Constructors and Destructors

### Singleton Classes&#x20;

Singletons are classes that **only permit one instance to exist**, the creation of **additional instances** are **prohibited**.

```cpp
class Singleton {
private:
    Singleton() {};  // private default constructor
    Singleton(const Singleton&); // private copy constructor 
    const Singleton& operator=(const Singleton&); // private copy assignment operator
    
    std::string name;
public:
    static Singleton& GetInstance() 
    {
        static Singleton instance;
        return instance;
    }
    
    std::string GetName() 
    {
        return name;
    }
    
    void SetName(string name)
    {
        this.name = name;
    }
}
```

### No-Copy Classes&#x20;

No copy classes are classes that prohibit being copied:

* through a pass-by-copy function parameter
* through an assignment operator&#x20;

This is done by making both the copy constructor and copy assignment operator **private**.

```cpp
class NoCopy {
private:
    NoCopy(const NoCopy&); // private copy constructor 
    NoCopy& operator= (const NoCopy&);  // private copy assignment operator
}
```

### Heap-Only Classes&#x20;

Heap only classes are classes that can only be instantiated **dynamically** (on the heap) and **never statically** (on the stack).&#x20;

This is done by declaring a private destructor, and exposing the destructor through a static member function.&#x20;

```cpp
class VeryLargeStructure {
private:
    ~VeryLargeStructure();  // private destructor

public:
    static void Destroy(VeryLargeStructure* instance) {
        delete instance;  // can be invoked here since it's within the class
    }
}
```

This is not a very common pattern, and is a remnant of older days where stack memory is limited, and expensive to unwind, compared to heap memory.&#x20;

## \`this\` Pointer

`this` is a reserved keyword applicable anywhere within the scope of a class, and contains the address of the object itself.&#x20;

This does not have many applications, other than being able to disambiguate between local variables and member methods with the same name:&#x20;

```cpp
struct Human {
    std::string name;
    
    Human(std::string name) {
        this->name = name;  // This is ok!
    }
};
```

Note that `this` is not available for `static` class methods, since static methods do not require an instance to invoke.&#x20;

## Size of a class&#x20;

The operator `sizeof()` is used to determine the amount of memory, in bytes, used by a specific type.

This operator can be used for classes too, and report the sum of bytes consumed by all the attributes contained within the class definition.

### Word Padding&#x20;

Let's use a worked example for this.&#x20;

## Friend Classes&#x20;

Member functions and attributes classified as `private` are not accessible from functions outside of the class.&#x20;

This rule can be waived for classes or functions declared as **friend classes or functions** using the keyword `friend`.

```cpp
class Human {
    std::string name;
    int age;
    friend void Describe(const Human& human);  // Friend function
public:
    Human(std::string name, int age) : name(name), age(age) {};
}

void Describe(const Human& human) {
    std::cout << human.name << " is " << human.age << " years old." << std::endl;
}
```

Friend functions are defined using the keyword `friend` followed by the **signature of the function** that is to be friended.

Friend classes are defined using the keyword `friend class` followed by the **name of the class** that is to be friended.

## Unions&#x20;

A `union` is a special class type where only one of its data members is active at a time. Thus, a `union` can a**ccommodate** multiple types of data members, but is **actually** only one of them.

### Declaring a Union&#x20;

```cpp
union DayInfoValue {
    char day;
    bool isRaining;
    float temperature;
}
```

### When to use a union

A union is often used as a **member of a struct or class** to model a complex data type.&#x20;

The benefits of using a union is that it saves space as opposed to storing each possible data as a separate attribute.&#x20;

```cpp
enum DayInfoType {
    DAY,
    RAIN,
    TEMPERATURE,
}

struct DayInfo {
    DayInfoType type;
    DayInfoValue value;
    
    void display() {
        switch (type):
            case DayInfoType::DAY:
                std::cout << "The day is " << value.day << std::endl;
                break;
            case DayInfoType::RAIN:
                std::cout << "Today " << (value.isRaining ? "is" : "is not") << " raining" << std::endl;
                break;
            case DayInfoType::TEMPERATURE:
                std::cout << "The temperature today is " << value.temperature << " celcius" << std::endl;
                break;
    }
}
```

## Aggregate Initialisation&#x20;

Aggregate initialisation is initialisation with curly braces.&#x20;

```cpp
// With value types
int a {3};
double b {5};
float b {a};

// With array types 
int nums[] = {5, 6, 10};
char word[6] = {'h', 'e', 'l', 'l', 'o', '\0'};
```

Aggregate initialisation can be applied to any **aggregate types**.&#x20;

Classes, structs, and unions are aggregates too.

There are some restrictions imposed by the C++ standard on the specification of `struct`s or `class`es that can be aggregates. But a safe definition:

* Classes and structs that comprise of only public and non-static data members
* Contains no private or protected data members&#x20;
* Contain no virtual member functions&#x20;
* Feature no or only public inheritance&#x20;
* No user-defined constructors&#x20;

can be aggregates.&#x20;

The following are valid aggregates:

```cpp
struct Foo {
    int integer;
    double decimal;
}

Foo myFoo {10, 10.2};
```

```cpp
struct Bar {
    int num;
    char word[6];
    int numbers[5];
}

Bar myBar {42, {'h', 'e', 'l', 'l', 'o', '\0'}, {2, 4, 6, 8, 10}};
```

{% hint style="info" %}
Aggregate initialisation should be avoided for unions, as it will only initialise the first member defined.&#x20;
{% endhint %}

## Forward Declaring Classes&#x20;

So far we've only **defined** classes. If we only wanted to declare a class for forward declaration purposes, we can do that.&#x20;

```cpp
class Foo {
    int x;
    Foo(int x);  // Delcaring a constructor (not implementing!)
    void bar();  // Declaring a member function (not implementing!) 
};

Foo::Foo(int x): x(x) {}; // Defining

void Foo::bar() {   // Defining
    std::cout << x << std::endl;
}
```

This is similar to declaring a function using its prototype, then defining it later.

```cpp
int sum(int x, int y);  // Declaring 

// ... 

int sum(int x, int y) {  // Implementing / defining 
    return x + y; 
}
```
