specifier override to indicate intention to override

Assume that you want override the Fish::Swim in Derived class but with a slightly different signature - one using const inserted unintentionally like the following

1
2
3
4
5
6
7
8
class Tuna: public Fish
{
public:
void Swim() const
{
cout << "Tuna swims" << endl;
}
};

this function actually does not override Fish::Swim(). Therefore, override supplies a powerful way of expressing the explicit intention to override a base class virtual function, thereby getting the compiler to check whether:

  • the base class function is virtual
  • the signature of the base class virtual function exactly matches that of the Derived class function declared to override.

using final to prevent function overriding

A class declared as final cannot be used as a base class, similarly, a virtual function declared as final cannot be overridden in a derived class.

Syntax

:

1
2
3
4
5
6
7
8
class Tuna: public Fish
{
public:
void Swim() override final
{
//...implementation
}
};

class Tuna in this snippet can be inherited from, but Swim() cannot be overridden any further.

virtual copy constructors

c++ does not allow usage of virtual copy constructors.

Having said that, there is a nice workaround in the form of defining your own clone function that allow you to do that:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Fish
{
public:
virtual Fish* Clone() const = 0; //pure virtual function
};

class Tuna: public Fish
{
public:
Tuna* Clone() const //virtual clone function
{
return new Tuna (*this);//return new Tuna that is copy if this
}
};

the this pointer

The this pointer is a pointer accessible only within the nonstatic member functions of a class, struct, union type. It points to the object for which the member function is called.

syntax

:

1
2
this
this->member-idetifier
type of the this pointer

The this pointer's type can be modified in the function declaration by keywords const and volatile. To declare a function that has either of these attributes, add the keywords after the function argument list.

consider an example:

1
2
3
4
5
6
7
8
9
10
class Point
{
public:
unsigned X() const;
};

int main()
{
//...implementation
}

The preceding code declares a member function X(), in which the this is treated as a const pointer to a const object.


Go ahead with virtual function clone, it's a simulated virtual copy constructor that needs to be explicitly invoked.

e.g. A clone function as a simulated virtual copy constructor demolist11_9

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <iostream>
using namespace std;

class Fish
{
public:
virtual Fish *Clone() = 0;
virtual void Swim() = 0;
virtual ~Fish(){};
};

class Tuna : public Fish
{
public:
Fish *Clone() override
{
cout << "new Tuna(*this) " << new Tuna(*this) << endl;
return new Tuna(*this);
}

void Swim() override final /*final*/
{
cout << "Tuna Swims" << endl;
}
};

class Crap final : public Fish
{
public:
Fish *Clone() override
{
cout << "new Crap(*this) " << new Crap(*this) << endl;
return new Crap(*this);
}

void Swim() override final
{
cout << "Crap Swims" << endl;
}
};

class secTuna final : public Tuna
{
public:
Fish *Clone() override
{
cout << "new secTuna(*this) " << new secTuna(*this) << endl;
return new secTuna(*this);
}
// Swim() cannot override swim() because it's `final` in Tuna
};

int main()
{
const int ARRAY_SIZE = 3;
Fish *myFish[ARRAY_SIZE] = {NULL};
myFish[0] = new Tuna();
myFish[1] = new Crap();
myFish[2] = new secTuna();

Fish *myNewFish[ARRAY_SIZE];
for (int index = 0; index < ARRAY_SIZE; ++index)
{
myNewFish[index] = myFish[index]->Clone();
cout << "myFish[" << index << "] " << myFish[index] << endl;
cout << "myNewFish[" << index << "] " << myNewFish[index] << endl;
}

for (int index = 0; index < ARRAY_SIZE; ++index)
{
myFish[index]->Swim();
}

for (int index = 0; index < ARRAY_SIZE; ++index)
{
delete myFish[index];
delete myNewFish[index];
}

return 0;
}

output

1
2
3
4
5
6
7
8
9
10
11
12
new Tuna(*this) 0x55ad513c1320
myFish[0] 0x55ad513c0eb0
myNewFish[0] 0x55ad513c1340
new Crap(*this) 0x55ad513c1360
myFish[1] 0x55ad513c0ed0
myNewFish[1] 0x55ad513c1380
new secTuna(*this) 0x55ad513c13a0
myFish[2] 0x55ad513c0ef0
myNewFish[2] 0x55ad513c13c0
Tuna Swims
Crap Swims
Tuna Swims

Comparing line 17 with line 65 and line 66, the address of new Tuna is expected to be allocated, whereas, the three have difference store address as the output line 1,2,3 demonstrates. myFish[0] get a address by using new Tuna() in line 57 before we call myFish->Clone() in line 64 of main. Therefore, myNewFish() is allocated to a address as well while calling. Line 18 can be interpreted as:

1
2
Base* X= new Base;
Y = X;

as the preceding snippet demonstrates, argument Y is a representation of myNewFish(), and X is the transit.

Additionally
[Why we can do : Base base = new Derived; while we can not do Derived derived = new Base?]

Remember mark functions in derived classes that are intended to override base functionality using keyword overridden.

Abstract base classes and pure virtual function.

  • a base class that cannot be instantiated is called an abstract base class. It fullfils only one purpose, that of being derived from.
  • e.g. virtual void BaseFunc () = 0;
Q

: Given an inheritance hierarchy, do I need to use the keyword virtual on all declarations of a virtual function or just in the base class.

A

: It is enough to declare a function as virtual once, but that declaration has to be in the base class. As long as a class has at least one pure virtual function, it remains an abstract base class(ABC) irrespective of the presence or absence of other fully defined functions or parameters.

exercise

Bug busters

Q

:what is the problem in the following code:

1
2
3
4
5
6
7
8
9
10
11
12
class Vehicle
{
public:
Vehicle() {}
~Vehicle(){}
};
class Car: public Vehicle
{
public:
Car() {}
~Car() {}
};
A

: doesn't have a virtual destructor. That can cause only one(car or vehicle) destructor invoked when it goes out of scope. e.g.

1
2
Vehicle* pMyRacer = new Car;
delete pMyRacer;

In this case nonvirtual destructor would result in only ~Vehicle invoked.

Correction

1
2
3
4
5
6
7
8
9
10
11
12
class Vehicle
{
public:
Vehicle() {}
virtual ~Vehicle(){} //add virtual keyword
};
class Car: public Vehicle
{
public:
Car() {}
~Car() {}
};