Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions content/cpp/concepts/classes/classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,78 @@ This will output:
Point(4, 6)
Points are equal: false
```

# Base class pointers

A base class pointer gives you the opportunity to create a [pointer](https://github.com/Codecademy/docs/blob/main/content/cpp/concepts/pointers/pointers.md) of type Base, and it can point to any type of class from that hierarchy (it needs to have the Is-A relationship).
If you use [dynamic polymorphism](https://github.com/Codecademy/docs/blob/main/content/cpp/concepts/polymorphism/polymorphism.md), then C++ will know exactly at runtime which function to call (based on the actual object the pointer points to).


It's easier to see it work in an example:

```cpp
#include <iostream>

class Base{
public:
static constexpr const char* message = "Base class. Cats are cute.\n";
static constexpr int num = 1;
static int x;
virtual void sayHi(){
std::cout << "Hello from " << message;
std::cout << "The number: " << num << "\n";
}
//good practice to have virtual destructors if your class uses virtual methods.
virtual ~Base() = default;
};

class Derived1 : public Base {
public:
static constexpr const char* message = "Derived 1 class. Indeed they are.\n";
static constexpr int num = 2;
//this is not called overloading anymore.
//this is called overriding.
virtual void sayHi() override{
std::cout << "Hello from " << message;
std::cout << "The number: " << num << "\n";
}
};

int Base::x = 999;

int main(){

Base* p1 = new Base();
Base* p2 = new Derived1();
p1->sayHi();
p2->sayHi();

std::cout << "\n";
std::cout << p2->x << "\n";
std::cout << p1->x << "\n";

}
```

The output:
```shell
Hello from Base class. Cats are cute.
The number: 1
Hello from Derived 1 class. Indeed they are.
The number: 2

999
999
```

As you can see:
* **p1** is a pointer of type Base. C++ will dynamically bound it and will use the method from the Base class.
* **p2** is a pointer of type Base that points to a Derived1 Object. Because "sayHi()" is virtual, C++ dynamically triggers the Derived1's own implementation of the "sayHi()" method.


## The keywords used:
* override (C++11) - specifies that this method is overridden, means if the signature of the method is **NOT** the same as the one from the base class, the compiler will throw an error **'virtual void Derived1::sayHi()' marked 'override', but does not override'**.
Why do we need this? Because to override methods, the signatures MUST be the same. If the derived method has a different signature, then that's not overriding anymore.
* default (C++11) - uses the compiler-generated version of the virtual destructor.
* static - it's a shared variable, it doesn't participate in polymorphism. Therefore the value will be the same in all instances.
* constexpr (C++11) - specifies that the value of the variable can be evaluated at compile-time.