csci-383 object-oriented programming & design lecture 18

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

Upload: madeleine-allen

Post on 05-Jan-2016

215 views

Category:

Documents


0 download

TRANSCRIPT

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

CSCI-383

Object-Oriented Programming & Design

Lecture 18

Page 2: CSCI-383 Object-Oriented Programming & Design Lecture 18

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 #5 Both of these classes contain an implementation of

the virtual method print

Page 3: CSCI-383 Object-Oriented Programming & Design Lecture 18

Virtual Functions Now let’s assume that we are given the following

declarationstimeOfDay tod(3, 45, 2.2);timeOfYear toy(30, 7, 14, 51.6);timeOfDay* tPtr1 = &tod;timeOfDay* tPtr2 = &toy;

Then the statementstod.print(cout);toy.print(cout);

will produce the output3:45:2.230:7:14:51.6

Page 4: CSCI-383 Object-Oriented Programming & Design Lecture 18

Virtual Functions

Because print is a virtual function, the statementstPtr1->print(cout);

tPtr2->print(cout);

will also produce the output3:45:2.2

30:7:14:51.6

Page 5: CSCI-383 Object-Oriented Programming & Design Lecture 18

Virtual Functions

What would happen if we let the keyword virtual out of the example interfaces?

The statementstPtr1->print(cout);

tPtr2->print(cout);

would produce the output3:45:2.2

7:14:51.6

Page 6: CSCI-383 Object-Oriented Programming & Design Lecture 18

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

Page 7: CSCI-383 Object-Oriented Programming & Design Lecture 18

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

Page 8: CSCI-383 Object-Oriented Programming & Design Lecture 18

Virtual Functions & References

The example in handout #5 also illustrates how one would use virtual functions with reference parameters 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

Page 9: CSCI-383 Object-Oriented Programming & Design Lecture 18

Virtual Functions & References

For example, using the variables defined in the earlier example, the statements

cout << tod << endl;

cout << toy << end;

will produce the output3:45:2.2

30:7:14:51.6

Page 10: CSCI-383 Object-Oriented Programming & Design Lecture 18

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

Page 11: CSCI-383 Object-Oriented Programming & Design Lecture 18

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

Page 12: CSCI-383 Object-Oriented Programming & Design Lecture 18

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;

}

Page 13: CSCI-383 Object-Oriented Programming & Design Lecture 18

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

Page 14: CSCI-383 Object-Oriented Programming & Design Lecture 18

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 statementtimeOfDay* tPtr1 = new timeOfYear(30,7,14,51.6);

What happens when one executes the following statement?

delete tPtr1;

Page 15: CSCI-383 Object-Oriented Programming & Design Lecture 18

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

Page 16: CSCI-383 Object-Oriented Programming & Design Lecture 18

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)

Page 17: CSCI-383 Object-Oriented Programming & Design Lecture 18

Virtual Destructors

In the example illustrated in handout #5, the derived class maintains a class variable that is used as an instance counter. The statementtimeOfDay* tPtr1 = new timeOfYear(30,7,14,51.6);

executes the constructors of timeOfDay and then timeOfYear, thus incrementing the class variable

However, the statementdelete tPtr1;

executes only the destructor of timeOfDay Thus, the class variable does not get decremented

Page 18: CSCI-383 Object-Oriented Programming & Design Lecture 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

Page 19: CSCI-383 Object-Oriented Programming & Design Lecture 18

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

Page 20: CSCI-383 Object-Oriented Programming & Design Lecture 18

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){ }

Page 21: CSCI-383 Object-Oriented Programming & Design Lecture 18

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