Thank you! But why does me having a pointer to a `Shark` as opposed to a `Fish` allow me to override the subclass method `doSwag` without a virtual key word? Shouldn't the compiler warn me about that or issue an error?
And true, thanks, I could store the object on the stack instead of the heap to discourage memory leaks.
There's no warning/error here. This is typical behavior.
Virtual functions examine the actual object type at runtime and call the appropriate function based on that.
Non-virtual functions simply look at the "apparent" type at compile time and call the appropriate function.
That said... here's an example of what I mean:
1 2 3 4 5 6 7 8 9 10 11 12 13
class Fish
{
public:
virtualvoid Virt() { ... }
void NonVirt() { ... }
};
class Shark : public Fish
{
public:
virtualvoid Virt() { ... }
void NonVirt() { ... }
};
Here we have a parent class 'Fish' and a child class 'Shark'.
Each class has 2 member functions, one virtual and one non-virtual
This means we have a total of 4 separate functions:
int main()
{
Shark topus; // topus is a Shark
Shark* sh = &topus; // sh is a pointer to a shark. In this case, it points to topus.
// now let's call each function and see what happens:
sh->NonVirt(); // The non virtual function call. We are acting on 'sh' which is of type
// Shark*. The compiler sees this, and so it calls the shark form of the function.
// therefore this calls function #4: Shark::NonVirt
sh->Virt(); // the virtual function call. This does not look at the type of 'sh', but rather
// it looks at the type that sh points to (ie: the "actual" type, not the perceived type).
// Here, since 'sh' points to 'topus', and 'topus' is of type 'Shark', this also calls the Shark
// form. Therefore this calls function #3: Shark::Virt
// now let's get tricky...
Fish* wanda = &topus; // wanda is a pointer to a fish. In this case, it points to topus
// note that topus is actually a Shark, but it's also a Fish because Shark derives from Fish
wanda->NonVirt(); // The non-virtual call. The compiler examines the type of 'wanda',
// which is of type 'Fish*'. Therefore this calls the Fish form of the function:
// function #2: Fish::NonVirt
wanda->Virt(); // The virtual call. This is where the virtual keyword is so useful.
// rather than just examining the type of 'wanda'... this actually will look at the object
// wanda points to in order to determine the actual type. Here, wanda points to topus.
// and we know that topus is ACTUALLY a Shark. Therefore this calls the Shark form
// instead of the Fish form. Therefore this calls function #3: Shark::Virt
}