We could say that Inheritance is the most important feature in C++
Remember that a "rule" states that a reference or pointer to a derived class object is converted to a reference or pointer to a base class object when used as an argument to a function defined as accepting a reference or a pointer to a base class object
Also, a base class pointer can point to a derived class object and that a base class reference can refer to a derived class object without an explicit type cast. But the reverse is not true, you can not have a derived class pointer or reference refer to a base class object without explicit type cast. Depending upon the class declarations, such an explicit type cast (a downcast) may or may not make sense
Today, we will talk about the "tool" that enhances the features of inheritance in C++ - Virtual function
When a compiler compiles the source code file containing the function definition, it has no way of knowing what type of object will be passed to it as an argument in some other file.
The only choice the compiler can make at compile time is to match class methods to the type of reference or pointer.
This strategy is called early binding, or static binding
The term binding refers to attaching a function call to a particular function definition
In C, you have only one function per name, so the choice is obvious for the compiler
In C++, with function overloading and redefined member functions, we can have more than once function matching a given name
A second stategy, called late binding, or dynamic binding is offered by C++
Compiler does not make decision of which class method to use
It passes responsibility to the program, which then makes a runtime decision whenever it actually executes a method function call (We will use the lab as example ...)
We can only turn on dynamic binding for member fucntion
Use the virtual keyword in the base class
Then, redefine the function in a derived class, a program then will use dynamic binding to determine which definition to use
Once it is a virtual method, if remains virtual for all classes derived from the base class
Thus, for a given method, you only have to use the keyword virtual once, in the base class
In a nutshell, virtual member functions are created by preceding the prototype with the keyword virtual. C++ programs then use dynamic, or late, binding for virtual methods, and static, or early, binding for nonvirtual methods.
Also, for virtual functions, the type of object referred to or pointed to determines which method to a pointer or reference invokes
// arraydbv.h -- revised array class, making [] virtual #ifndef _ARRAYDB_H_ #define _ARRAYDB_H_ #include <iostream.h> class ArrayDb { private: unsigned int size; // number of array elements protected: double * arr; // address of first element public: ArrayDb(); // default constructor // create an ArrayDb of n elements, set each to val ArrayDb(unsigned int n, double val = 0.0); // create an ArrayDb of n elements, initialize to array pn ArrayDb(const double * pn, unsigned int n); ArrayDb(const ArrayDb & a); // copy constructor virtual ~ArrayDb(); // destructor unsigned int arsize() const {return size;}// returns array size // overloaded operators -- note use of keyword virtual virtual double & operator[](int i); // array indexing virtual const double & operator[](int i) const; // array indexing (no =) ArrayDb & operator=(const ArrayDb & a); friend ostream & operator<<(ostream & os, const ArrayDb & a); }; #endif
If dynamic binding is so cool, when even have static binding ?
Efficiency, for making dynamic binding decision, program has to keep track of what sort of object a base class pointer or reference refers to, and that entails some extra processing overhead
Second, without making a function virtual, that means we announce that it is our intention that this function not be redefined. Thus, we have control over our class design
In short, if a method in a base class will be redefined in a derived class, make it virtual. If the method should not be redefined, make it nonvirtual
// Syntax Exampleclass Employee { public: virtual void showme(int a) const; ... }class Programmer : public Employee { public: void showme(int a) const; ... }
C++ has a variation of the virtual function call a "pure virtual function"
It is a virtual function with a prototype but no definition
Syntax:
class Shape { public: virtual void draw() const = 0; virtual double area() const - 0; ... }When a class declaration contains a pure virtual function, you cannot create an object of that class. So, the idea of pure virtual function only exist in base class
The base class of the pure virtual function then is called abstract base class (ABC)
For example, Shape will be a good candiate for ABC, since there is actually no "Shape" in the real world. There might be Triangle, Rectangle or Circle ... but not Shape
As a matter of fact, ABC can be used to describes an interface in terms of pure virtual functions, can a class derived from an ABC uses regular virtual functions to implement the interface in terms of the properties of the particular derived class
Full example in lab
This is a programming short cut in a sense (this topic is included for completion, it is not directly related to inheritance, however, quite a few people use this technique for quick virtual member function)
Inline function is a C++ enhancement designed to speed up programs
Use does not need to change the way he/she codes, C++ compiler will incorporate them (inline functions) into a program
When normal function is called, processor will usually save all the register information, memory information, then jump to the location of the function (at that point, it will be some session of machine code)
When the normal function finish execution, it will then restore all the registers and memory information, then jump back to the point in the program after the function execution
With C++ inline function, C++ compiler compiles the function "in line" with the other code in the program
The compiler replaces the function call with the corresponding function code in the machine language level, so no jump of function call is necessary
Run a little faster depend on system
BUT, there is a memory penalty. If a program calls an inline function ten times, then the program winds up with ten copies of the function inserted into the code
Use inline function selectively in order to take the advantages
To use inline function, we have to do
Preface the function definition with the keyword inline
Place the function definition above all the functions that call it
OR define the function in the header files (as in the lab)
Note that you have to place the entire definition (meaning the function header and all the function code), not just the prototype, above the other functions
The compiler does not have to honor your request to make a function inline. It may decide the function is too large or notice that it calls itself (recursion is not allowed for inline functions), or the feature may not be implemented for your particular compiler
Example:
// inline.cpp -- use an inline function #include <iostream.h> // an inline function must be defined before first use inline double square(double x) { return x * x; } int main(void) { double a, b; double c = 13.0; a = square(5.0); b = square(4.5 + 7.5); // can pass expressions cout << "a = " << a << ", b = " << b << "\n"; cout << "c = " << c; cout << ", c squared = " << square(c++) << "\n"; cout << "Now c = " << c << "\n"; return 0; }
Shape.hpp (class definition and implementation)
Circle.hpp (class definition and implementation)