Inheritance Discovery
Syntax and facts:
Inheritance syntax on a class:
One class inherits another by placing " : modifier classname being inherited
" after the classname and including the base class header.
- #include "Mother.h"
- class Daughter : public Mother { }
C++ allows multiple inheritance using
- #include "Mother.h"
- #include "Person.h"
- class Daughter : public Mother , public Person{ }
public / protected / private:
- modifier on variables and methods: Inherited classes can be thought to physically
contain everything the parent contains, but they cannot touch private variables
and methods. Public and protected methods can be touched by the child (derived
class)
- public - anyone; private - only the class itself and friends; protected
- the class itself, friends, children
- modifier in the class line: The modifier in the class line (class daughter:
public) is used to demote all higher level privileges to the given level for
those using the child class.
- example: class daughter: protected mother takes every public access
variable and converts it to protected access to anyone creating objects
or extending daughter.
- This means using "public" means no change to the existing
parent (base class) modifiers, as it is the least privileged.
constructor:
- Parent constructor runs before the constructor function begins. Any adjustments
must happen before the functions {}.
- To send parameters to the parent constructor: After the construction function
name, place " : base class name ( parms ) " before {.
- ex: Daughter( string daughter_name, string mother_name ) : Mother (mother_name)
{ this->name = daughter_name; }
defining functions in the derived (child) class:
- override a parent function by using the same signature
- execute a parent function by specifying the class : ex Mother::print()
should class inherit or contain:
- Inherit: Add features to an existing class to override or implement its
functions. derived is a type of base
- Contain an object: Create an object as an instance variable to use it in
a new class. new class has a base object.
polymorphism: pointers and references of base types can hold derived types,
but not the reverse:
- Make a derived object:
- Triangle triangle(3,4,5);
- Place derived object in base pointer variable:
- Shape * shapePtr = ▵
- float area = shapePtr->area();
- Place derived object in base reference variable:
- Shape & shapeRef = triangle;
- float area = shapeRef.area();
virtual:
- put the keyword virtual before a function to tell the class that it should
use derived class override function if possible
- put " = 0" after the method header (before ;) to indicate it is
abstract and will not be implemented in the base class
- virtual int area ( ) = 0;
- cannot create objects of classes with pure virtual functions, but can
create pointers and references
- keyword virtual inherits and cannot be overwritten, so write virtual in
all derived functions of
- sidenote: a class with ANY virtual functions should have a virtual destructor.
- sidenote: constructors cannot be virtual.
- virtual allows dynamic (run time) binding instead of forcing static (compile
time) binding
Arrays (vectors)
- Create an array of pointers using vector < classname * > variable
name (size)
- vector < Shape * > shapeArr (3)
- Access vector element with [ ] without dereferencing
Dynamic downcast:
- dynamic_cast < classname or classname * > (variable)
- Triangle * trianglePtr = dynamic_cast <Triangle *> (shapePtr)
;
- must include <typeinfo>
- sets nullptr if it cannot cast:
- if (trianglePtr == nullptr ) {cout << "downcast did not work"
; }
Determine type:
- Get true type of object, not variable using : typeid ( variable address
- or pointer ).name( )
- cout << typeid(shapePtr).name();
Task: Fill in the grid below using a set of classes and test driver programs
that you create:
Create a set of shape classes with Shape being an abstract class from which
triangle and rectangle are derived. (You can also derive square from rectangle
as well to add one more level.)
Use these classes to fill in the grids below: To do this, do not use pure virtual
functions.
|
Base Class |
Derived Class function |
variable pointer type |
variable type |
used base or derived function? |
1 |
virtual function |
virtual function |
base |
base
|
|
2 |
not a virtual function |
virtual function |
base |
base |
|
3 |
not a virtual function |
not a virtual function |
base |
base |
|
4 |
virtual function |
virtual function |
base |
derived |
|
5 |
not a virtual function |
virtual function |
base |
derived |
|
6 |
not a virtual function |
not a virtual function |
base |
derived |
|
|
|
|
|
|
|
|
|
|
|
|
|
First verify you can create an object of the base type. Then make your virtual
function in your base class a pure virtual function by adding = 0 and removing
the implementation. Fill out the grid below:
|
Can you create a variable of the type (not a pointer to the type) of the
base? |
Can you create a variable of the type (not a pointer to the type) of the
derived? |
base contains pure virtual |
|
|
base does not contain pure virtual |
|
|
public/ private / protected exploration: optional
Make three base variables private, protected and public access levels. Inherit
the base in a derived class at a private level. Create a driver program to create
one object of the base and one of the derived class. Experiment to fill in the
grid below
and then fill in this grid about a private derived inheritance:
base |
Can the derived class access the variables using dot notation? |
Can the driver program access the variables of a base object using dot
notation? |
Can the driver program access the variables of a derived object using
dot notation? |
public |
|
|
|
private |
|
|
|
protected |
|
|
|
If you change the derived class to public inheritance (on the class line) does
it change your answers?