Download presentation
Presentation is loading. Please wait.
Published byChristal Miles Modified over 9 years ago
1
Virtual FunctionstMyn1 Virtual Functions A virtual function is declared in a base class by using the keyword virtual. A function that you declare as virtual in a base class will also be a virtual function in all classes derived (either directly or indirectly) from the base. To obtain polymorphic behaviour, each derived class may implement its own version of the virtual function.
2
Virtual FunctionstMyn2 class Box { public: virtual double volume() const; … }; class otherBox: public Box { public: virtual double volume() const; … }; class ToughPack: public Box { public: virtual double volume() const; … }; class Carton: public Box { public: virtual double volume() const; … }; pbox is type pointer to Box. The version of volume() function called is dependent on the type of object pointed to by pbox. double result= pbox->volume(); Diagram 1. Illustration of how a call to a virtual function through a pointer is resolved dynamically.
3
Virtual FunctionstMyn3 Virtual function calls can be made using a variable that is a pointer or a reference to a base class object. In the diagram 1 the pointer to base is used to store the address of an object with a type corresponding to one of the derived classes. It could point to an object of any of the three derived classes shown, or of course to a base class object. Which volume() function is called will depend on the type of the object to which the pointer points when the call is executed. Describing a class as polymorphic means that it’s a class that contains at least one virtual function.
4
Virtual FunctionstMyn4 Note that a call to a virtual function using an object will always be resolved statically. You only get dynamic resolution of calls to virtual functions through a pointer or a reference. Let’s make a very small change to the Box class: we just need to add the keyword virtual to the declaration of the calcVol() function (and for the sake of symmetry, same keyword to the derived class):
5
Virtual FunctionstMyn5 #include "stdafx.h" #include using namespace System; using namespace std; class Box { public: Box(); Box(double, double, double); ~Box(); void displayVol(); virtual double calcVol() const; protected: double length; double breadth; double height; }; We can declare the functions as const because they do not alter any data members of the class. The keyword virtual in the base class definition of the function volume() is sufficient to determine that all declarations of the function in derived classes will also be understood to be virtual.
6
Virtual FunctionstMyn6 Box::Box() { cout<<"Base class default constr., object "<<this<<endl; cout<<"Length: "; cin>>length; cin.get(); cout<<"Breadth: "; cin>>breadth; cin.get(); cout<<"Height: "; cin>>height; cin.get(); } Box::Box(double lv, double bv, double hv) { cout<<"Base class constructor with 3 params., object ” <<this<<endl; length=lv; breadth=bv; height=hv; }
7
Virtual FunctionstMyn7 Box::~Box() { cout<<"Base class destructor, object "<<this<<endl; } void Box::displayVol() { cout<<"Usable volume is "<<calcVol()<<endl; } double Box::calcVol() const { return length*breadth*height; } Do not add the virtual keyword to the function definition!
8
Virtual FunctionstMyn8 class Carton:public Box { public: Carton(); Carton(string); Carton(double, double, double, string); ~Carton(); virtual double calcVol() const; private: string* text; }; Carton::Carton():Box() { cout<<"Derived class default constr., object "<<this<<endl; text=new string; cout<<"Typical usage: "; getline(cin, *text); }
9
Virtual FunctionstMyn9 Carton::Carton(string message):Box() { cout<<"Derived class constructor with 2 params, object " <<this<<endl; text=new string; *text=message; } Carton::Carton(double lVal, double bVal, double hVal, string message):Box(lVal, bVal, hVal) { cout<<"Derived class constructor with 4 params., object ” <<this<<endl; text=new string; *text=message; }
10
Virtual FunctionstMyn10 Carton::~Carton() { cout<<"Derived class destructor, object "<<this<<endl; delete text; text=0; } double Carton::calcVol() const { return 0.85*length*breadth*height; }
11
Virtual FunctionstMyn11 int main(array ^args) { Box first=Box(); Carton second=Carton(); Box* pBox=&first; pBox->displayVol(); pBox=&second; pBox->displayVol(); return 0; }
12
Virtual FunctionstMyn12
13
Virtual FunctionstMyn13 It is recommended that you do use the keyword virtual with all declarations of virtual functions in derived classes, since it makes it clear to anyone reading the derived class definition that the functions are indeed virtual, and that they will be linked to dynamically. Let’s make two more tests:
14
Virtual FunctionstMyn14 int main(array ^args) { Box first=Box(); Carton second=Carton(); first.displayVol(); second.displayVol(); return 0; } This simply calls the base class version of calcVol(), since first is of type Box.
15
Virtual FunctionstMyn15
16
Virtual FunctionstMyn16 So the statement second.displayVol() calls the displayVol() function defined in the Box class – there aren’t any other versions of displayVol()! However, the call to calcVol() in displayVol() is resolved to the version defined in the derived class, because object second is of type Carton.
17
Virtual FunctionstMyn17 For a function to behave virtually you must declare and define it with the same name and parameter list in any derived class as it has in the base class. Further, if you have declared the base class function as const, then you must declare the derived class function to be const as well.
18
Virtual FunctionstMyn18 To ensure that the correct destructor is called for objects allocated in the free store, we need to employ virtual class destructors. To implement a virtual class destructor, we just add the keyword virtual to the destructor declaration in the class. This signals to the compiler that destructor calls through a pointer or a reference parameter should have dynamic binding, and so the destructor will be selected at runtime.
19
Virtual FunctionstMyn19 This works in spite of the fact that all the destructors have different names; destructors are treated as a special case for this purpose. Recall the example:
20
Virtual FunctionstMyn20 … int main(array ^args) { Box* first=new Carton(); delete first; return 0; }
21
Virtual FunctionstMyn21 Unfortunately the derived class destructor will never be called!
22
Virtual FunctionstMyn22 Let’s add the keyword virtual to the base class destructor declaration:
23
Virtual FunctionstMyn23 … class Box { public: Box(); Box(double, double, double); virtual ~Box(); void displayVol(); virtual double calcVol() const; protected: double length; double breadth; double height; }; … This is the only difference compared to the previous one!!
24
Virtual FunctionstMyn24 … class Carton:public Box { public: Carton(); Carton(string); Carton(double, double, double, string); virtual ~Carton(); virtual double calcVol() const; private: string* text; }; … But we are free to have symmetry…
25
Virtual FunctionstMyn25 int main(array ^args) { Box* first=new Carton(); delete first; return 0; }
26
Virtual FunctionstMyn26
27
Virtual FunctionstMyn27 Why would anyone use a reference or pointer of base class type to access an object of a subclass? Suppose we need to construct a function that will work with all subclasses of a base class. With polymorphism, the function could be coded to expect a pointer or reference to the base class type and behave correctly and distinctly when different subclasses are passed in. As a second example, suppose we wish to make a list or array containing references or pointers to objects of different subtypes of a single base class.
28
Virtual FunctionstMyn28 If the type of the array is selected to be either reference or pointer of the base class, subclasses of multiple types can be stored. And more importantly, the pointers or references will behave correctly and distinctly according to what subclass they access. This is polymorphism. So, in C++, the first requirement for polymorphism is that the objects must be accessed via pointer or reference.
29
Virtual FunctionstMyn29 A second requirement for polymorphism to work is that the functions whose polymorphic behaviour is desired must be declared as virtual. Overridden functions not declared as virtual (=redefinition) will behave correctly only for statically bound objects; those known at compile time. For base class pointers or references bound to objects during execution, polymorphism will not be seen if a function is not declared virtual.
30
Virtual FunctionstMyn30 Overriding When a virtual function definition is changed in a derived class, then the function definition is said to be overridden. A distinction is sometimes made between the terms redefined and overridden. Both terms refer to changing the definition of the function in a derived class. If the function is a virtual function, it is called overriding. If the function is not a virtual function, it is called redefining.
31
Virtual FunctionstMyn31 If a class declares any virtual functions, the destructor of the class should be declared as virtual as well. This ensures that regardless of the actual subclass of an object accessed via a base class pointer or reference, the correct destructor will clean it up.
32
Virtual FunctionstMyn32 Why not declare all functions as virtual? This could be done, but involves additional overhead. The compiler creates a virtual function table that is used in the polymorphism mechanism. Avoiding unnecessary details, the more functions that are declared as virtual, the greater the overhead to create and maintain these tables. But, by declaring all functions virtual, redesign may be avoided if the classes need to change. Some C++ programmers declare all functions virtual if any need be. Some don't. In some programming languages, such as Java, all functions are virtual by default.
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.