Presentation is loading. Please wait.

Presentation is loading. Please wait.

CSCI-383 Object-Oriented Programming & Design Lecture 18.

Similar presentations


Presentation on theme: "CSCI-383 Object-Oriented Programming & Design Lecture 18."— Presentation transcript:

1 CSCI-383 Object-Oriented Programming & Design Lecture 18

2 Virtual Functions  To see more examples of how virtual functions are used, let’s develop another inheritance hierarchy: the base class is timeOfDay, and its derived class is timeOfYear  This hierarchy is illustrated in handout #5handout #5  Both of these classes contain an implementation of the virtual method print

3 Virtual Functions  Now let’s assume that we are given the following declarations timeOfDay tod(3, 45, 2.2); timeOfYear toy(30, 7, 14, 51.6); timeOfDay* tPtr1 = &tod; timeOfDay* tPtr2 = &toy;  Then the statements tod.print(cout); toy.print(cout); will produce the output 3:45:2.2 30:7:14:51.6

4 Virtual Functions  Because print is a virtual function, the statements tPtr1->print(cout); tPtr2->print(cout); will also produce the output 3:45:2.2 30:7:14:51.6

5 Virtual Functions  What would happen if we let the keyword virtual out of the example interfaces?  The statements tPtr1->print(cout); tPtr2->print(cout); would produce the output 3:45:2.2 7:14:51.6

6 Diversity in the Workspace  One of the ways we can use virtual functions is to create an array of base class pointers and use it as an array of “elements” of diverse types  Could this be done in ANSI C? Certainly! One could create an array of void* elements and point them to instances of various structures  But how would one later know the types of the particular structure instances? Some possibilities include Point at a union of the possible structure types. Then, keep a flag to indicate the structure type of the data currently stored in the union Begin all structures with a flag to indicate its structure type; then, with lots of casting check the flag and treat the block of memory as the appropriate structure type

7 Diversity in the Workspace  Both of these solutions require the user to keep track of the type of the data. This is unnecessary when one uses virtual functions in C++  The only restriction is that all of the various types would have to be kept in the same inheritance hierarchy  One might even want to define a method named something such as whatTypeAmI that determines the type of an instance for use in conditional statements

8 Virtual Functions & References  The example in handout #5 also illustrates how one would use virtual functions with reference parametershandout #5 The base class timeOfDay has a friend function, the overloaded operator<< The second parameter of this function is a reference to a base class instance The overloaded operator then calls the appropriate version of print

9 Virtual Functions & References  For example, using the variables defined in the earlier example, the statements cout << tod << endl; cout << toy << end; will produce the output 3:45:2.2 30:7:14:51.6

10 Pure Virtual Functions  A class that is too generic to be instantiated is called an abstract class  Some methods might be identified in an abstract class, but not implemented in that class  A C++ method that is identified, but not implemented in a base class is called a pure virtual function

11 Pure Virtual Functions  A pure virtual function generally has a NULL implementation. For example virtual void print(ostream& cout) = 0;  This NULL implementation is located in the interface of the class  The declaration of a pure virtual function in a class forces the class to be an abstract class  If a pure virtual function declared in a base class is not implemented in a derived class, then the derived class is an abstract class too

12 Constructors Can’t Be Virtual  Constructors aren’t inherited and can’t be virtual  Constructors are very tightly bound up with a class and each class has its own unique set of constructors  It is non-sensical to declare a constructor virtual since a constructor is always called by name (e.g., ( timeOfDay(...), timeOfYear(...) ) so there is no choice about which version to invoke timeOfYear& timeOfYear::operator=(const timeOfYear& t){ if(this != &t) { timeOfDay::operator=(t); // do rest of timeOfYear copying here } return *this; }

13 operator= is not inherited either  This method is also very tightly coupled with a class  Remember that, just like with constructors, if you don’t provide an overloading of operator=, a default one is automatically provided  If you choose to implement your own version, you should invoke the parent class to do the parent’s part of the assignment

14 Virtual Destructors  Normally, when one deletes an instance of a derived class (e.g., timeOfYear ), the destructors of the derived class and those of all the ancestor classes are executed (in this case, the timeOfDay destructor)  But let’s assume that we are given the following statement timeOfDay* tPtr1 = new timeOfYear(30,7,14,51.6);  What happens when one executes the following statement? delete tPtr1;

15 Virtual Destructors  Since the classes involved in the example do not have virtual destructors, only the timeOfDay destructor is executed!  Further, if additional classes appeared in the hierarchy between timeOfYear and timeOfDay, their destructors would not be executed, either  This behavior can lead to memory leaks and other unpleasantries, especially when dynamic memory or class variables are managed by the derived class  A solution to the problem is the use of virtual destructors

16 Virtual Destructors  A virtual destructor is simply a destructor that is declared as a virtual function  If the destructor of a base class is declared as virtual, then the destructors of all its descendant classes become virtual, too (even though they do not have the same names)

17 Virtual Destructors  In the example illustrated in handout #5, the derived class maintains a class variable that is used as an instance counter. The statementhandout #5 timeOfDay* tPtr1 = new timeOfYear(30,7,14,51.6); executes the constructors of timeOfDay and then timeOfYear, thus incrementing the class variable  However, the statement delete tPtr1; executes only the destructor of timeOfDay  Thus, the class variable does not get decremented

18 Virtual Destructors  Rules of thumb for virtual destructors If any class in a hierarchy manages class variables or dynamic memory, make its destructor virtual If none of the classes in a hierarchy have user- defined destructors, do not use virtual destructors

19 Pure Virtual Destructors  Ass odd as it may seem, there are times when one may want to define a pure virtual destructor. Why?  One may want to force a class to be an abstract class though it has no pure virtual functions. A pure virtual destructor will do this  It also could be the case that the class is already an abstract class, but one wants to assure that the destructors in the hierarchy are virtual

20 Pure Virtual Destructors  As one might expect, a pure virtual destructor for class timeOfDay would be declared as follows in the class interface virtual ~timeOfDay(void) = 0;  However, unlike other pure virtual functions, one also must provide an empty implementation for pure virtual destructors timeOfDay::~timeOfDay(void){ }

21 Virtual Functions: Hidden Details  Instances of classes that have virtual functions must retain “behind the scenes” data to identify the class to which they belong. This information is used to look up appropriate method implementations at run time  In C++, this data consists of a vtbl (virtual function table) pointer. The vtbl pointer points to an array of vptr (virtual function pointer) values (one sometimes sees the word functor used as a synonym for function pointer)  Thus, when one defines virtual functions in a class, space and time overhead is incurred


Download ppt "CSCI-383 Object-Oriented Programming & Design Lecture 18."

Similar presentations


Ads by Google