250 likes | 523 Views
Junaed Sattar November 10, 2008 Lecture 10. Virtual Functions. Constructor/Destructor Order. Destructors, constructors, and assignment operators are not inherited they may be called automatically were necessary Constructors are called from the “bottom up”
E N D
Junaed Sattar November 10, 2008 Lecture 10 Virtual Functions
Constructor/Destructor Order • Destructors, constructors, and assignment operators are not inherited • they may be called automatically were necessary • Constructors are called from the “bottom up” • Destructors are called from the “top down”
Example • class Base {public:Base() { cout << "calling base constructor." << endl; }~Base() { cout << "calling base destructor." << endl; }}; • class Derived1: public Base{public:Derived1() { cout << "calling derived1 constructor." << endl; }~Derived1() { cout << "calling derived1 destructor." << endl; }}; • class Derived2 :public Derived1{public:Derived2() { cout << "calling derived2 constructor." << endl; }~Derived2() { cout << "calling derived2 destructor." << endl; }}; • int main(){ Derived2 d; • }
Output • calling base constructor. • calling derived1 constructor. • calling derived2 constructor. • calling derived2 destructor. • calling derived1 destructor. • calling base destructor.
Virtual Functions • C++ matches a function call with the correct function definition at compile time • known as static binding • the compiler can match a function call with the correct function definition at run time • known as dynamic binding. • declare a function with the keyword virtual if you want the compiler to use dynamic binding for that specific function.
Virtual Methods • Therefore, • a virtual function is a member function you may redefine for other derived classes, • can ensure that the compiler will call the redefined virtual function for an object of the corresponding derived class, • even if you call that function with a pointer or reference to a base class of the object. • A class that declares or inherits a virtual function is called a polymorphic class.
Declaring virtual • prefix declaration with the virtual keyword • redefine a virtual member function in any derived class • this is called overriding • understand the contrast with overloading
More on definition • overridden function must have same name and same parameter list • no need to use the virtual keyword again • return type can be different • if the parameter lists are different, they are considered different • in this case, it is not overridden, but hidden • hidden methods cannot be called
Example • class A {public:virtual void f() { cout << "Class A" << endl; }}; • class B: public A { • public:void f(int) { cout << "Class B" << endl; }}; • class C: public B { • public:void f() { cout << "Class C" << endl; }};
Output • int main() {B b; C c;A* pa1 = &b;A* pa2 = &c;// b.f();pa1->f();pa2->f();} • Outputs: • Class A • Class C
Synopsis • b::f() is not allowed • it hides A::f() (a virtual function) • not overloading (why?) • method overloading must happen within the same class, not in inheritance hierarchies • c::f() is allowed • virtual, overrides A::f()
So, why? • a hierarchy of geometric shape classes • draws circles, ellipses, rectangles etc • just use method draw throughout the hierarchy Line draw() Rectangle Circle draw() draw() Square Ellipse draw() draw()
More why • to enforce a software design • developers must define their own implementation • e.g. ImagingDevice objects (webcam, firewire, disk images, movies ..) • must acquire frames in their own way • should have uniform interface (hiding implementation details) • use pure virtual methods
“Pure”ly Virtual • a virtual function declared with no definition • base class contains no implementation at all • class containing a pure virtual function is an abstract class • similar to Java interfaces • cannot instantiate from abstract classes • enforces a design through inheritance hierarchy • inherited classes must define implementation
Example • class A {public:virtual void f() = 0; // pure virtual}; • class B: public A { • public:void f() { cout << "Class B" << endl; }}; • class C: public B { • public:void f() { cout << "Class C" << endl; }};
Output • int main() {B b; C c;A* pa1 = &b;A* pa2 = &c;pa1->f();pa2->f();} • Outputs: • Class B • Class C
Another example • class ImagingDevice {protected: unsigned char *buffer; int width, height; ...public: ImagingDevice(); virtual ~ImagingDevice(); // virtual destructor ... virtual bool InitializeDevice() = 0; virtual bool GetImage()=0; virtual bool UninitializeDevice() = 0; virtual void SaveImage()=0; ...};
Continuing • class USBDevice: public ImagingDevice { ...public: USBDevice(); virtual ~USBDevice();...};bool USBDevice::InitializeDevice(){ ... }bool USBDevice::UninitializeDevice(){ ... }bool USBDevice::GetImage(){ ... }void USBDevice::SaveImage(){ ... }
Why virtual destructor? • for properly cleaning up dynamically allocated memory class Base{public: Base(){} ...}; class Derived: public Base { int *memory;public: Derived(){ memory = new int[1000]; } ~Derived(){ delete [] memory; }}
Virtual Destructor • int foo() {Base *b = new Derived();...delete b; // will not call destructor of d, as it • // should, (why?) • }
Diagnosis • If not declared virtual, compiler uses type of pointer to decide which method to call • in this case, b is of type Base, so the Base destructor will get called • memory leak from d (how?) • solution: always declare destructors virtual, even if no other virtual functions
Next • Generic programming with templates • The Standard Template Library