• A virtual function is a member function that is declared within a base
class and redefined by a derived class. • virtual functions implement the "one interface, multiple methods" philosophy that underlies polymorphism • virtual functions important and capable of supporting run-time polymorphism is how they behave when accessed via a pointer Pointers to Derived Types #include <iostream> int main() using namespace std; { class base { base *bp; int i; derived d; public: bp = &d; // base pointer points to derived void set_i(int num) { i=num; } object int get_i() { return i; } // access derived object using base pointer }; bp->set_i(10); cout << bp->get_i() << " "; class derived: public base { /* The following won't work. You can't int j; access element of public: a derived class using a base class pointer. void set_j(int num) { j=num; } bp->set_j(88); // error cout << bp->get_j(); // error int get_j() { return j; } */ }; return 0; } Solution to the problem The pointer can be type casted and used to access the derived class members.
• // access now allowed because of cast
((derived *)bp)->set_j(88); cout << ((derived *)bp)->get_j(); Sample program #include <iostream> int main() using namespace std; { class base { base *p, b; public: derived1 d1; virtual void vfunc() { derived2 d2; cout << "This is base's vfunc().\n"; // point to base } p = &b; }; p->vfunc(); // access base's vfunc() class derived1 : public base { // point to derived1 public: p = &d1; void vfunc() { p->vfunc(); // access derived1's vfunc() cout << "This is derived1's vfunc().\n"; // point to derived2 } p = &d2; }; p->vfunc(); // access derived2's vfunc() class derived2 : public base { return 0; public: } void vfunc() { cout << "This is derived2's vfunc().\n"; } }; • Name Type p base class pointer b object of base d1 object of derived1 d2 object of derived2 • The key point here is that the kind of object to which p points determines which version of vfunc() is executed. • this determination is made at run time, and this process forms the basis for run-time polymorphism. Calling a Virtual Function Through a Base Class Reference #include <iostream> // Use a base class reference parameter. using namespace std; class base { void f(base &r) { public: r.vfunc(); virtual void vfunc() { } cout << "This is base's vfunc().\n"; } int main() }; { base b; class derived1 : public base { derived1 d1; public: derived2 d2; void vfunc() { f(b); // pass a base object to f() cout << "This is derived1's vfunc().\n"; f(d1); // pass a derived1 object to f() } f(d2); // pass a derived2 object to f() }; return 0; } class derived2 : public base { public: void vfunc() { cout << "This is derived2's vfunc().\n"; } }; The Virtual Attribute Is Inherited /* derived2 inherits virtual function vfunc() • from derived1. */ When a virtual function is inherited, its class derived2 : public derived1 { virtual nature is also inherited public: // vfunc() is still virtual Eg: void vfunc() { #include <iostream> cout << "This is derived2's vfunc().\n"; using namespace std; } 450 C + + : T h e C o m p l e t e R e f e r e n c e }; class base { public: int main() virtual void vfunc() { { cout << "This is base's vfunc().\n"; base *p, b; } derived1 d1; }; derived2 d2; class derived1 : public base { // point to base public: p = &b; void vfunc() { p->vfunc(); // access base's vfunc() cout << "This is derived1's vfunc().\n"; // point to derived1 } p = &d1; }; p->vfunc(); // access derived1's vfunc() // point to derived2 p = &d2; p->vfunc(); // access derived2's vfunc() return 0; } Output This is base's vfunc(). This is derived1's vfunc(). This is derived2's vfunc(). Virtual Functions Are Hierarchical • A function declared as virtual by a base class need not be overridden • When a derived class fails to override a virtual function, then when an object of that derived class accesses that function, the function defined by the base class is used #include <iostream> int main() using namespace std; { class base { base *p, b; public: derived1 d1; virtual void vfunc() { derived2 d2; cout << "This is base's vfunc().\n"; // point to base } p = &b; }; p->vfunc(); // access base's vfunc() // point to derived1 class derived1 : public base { p = &d1; public: p->vfunc(); // access derived1's vfunc() void vfunc() { // point to derived2 cout << "This is derived1's vfunc().\n"; p = &d2; } p->vfunc(); // use base's vfunc() }; return 0; } class derived2 : public base { public: // vfunc() not overridden by derived2, base's is used }; • Sample output This is base's vfunc(). This is derived1's vfunc(). This is base's vfunc().
• inheritance is hierarchical => virtual functions are also hierarchical.
• when a derived class fails to override a virtual function, • the first redefinition found in reverse order of derivation is used. Pure Virtual Functions • A pure virtual function is a virtual function that has no definition within the base class. • To declare a pure virtual function, use this general form: virtual type func-name(parameter-list) = 0;
• When a virtual function is made pure, any derived class must
provide its own definition. • If the derived class fails to override the pure virtual function, a compile-time error will result. #include <iostream> class octtype : public number { using namespace std; public: class number { void show() { protected: cout << oct << val << "\n"; int val; } public: }; void setval(int i) { val = i; } // show() is a pure virtual function int main() virtual void show() = 0; { }; dectype d; hextype h; class hextype : public number { octtype o; public: d.setval(20); void show() { d.show(); // displays 20 - decimal cout << hex << val << "\n"; h.setval(20); } h.show(); // displays 14 - hexadecimal }; o.setval(20); o.show(); // displays 24 - octal class dectype : public number { return 0; public: } void show() { cout << val << "\n"; } }; Abstract Classes • A class that contains at least one pure virtual function is said to be abstract. • no objects of an abstract class may be created. • pointers and references to an abstract class can be created. • This allows abstract classes to support run-time polymorphism. Using Virtual Functions • Uses the principle of "one interface, multiple methods." • a general class of actions can be defined, the interface to which is constant, with each derivation defining its own specific operations. // Virtual function practical example. // Fahrenheit to Celsius #include <iostream> class f_to_c : public convert { using namespace std; public: f_to_c(double i) : convert(i) { } class convert { void compute() { protected: val2 = (val1-32) / 1.8; double val1; // initial value } double val2; // converted value }; public: convert(double i) { int main() val1 = i; { } convert *p; // pointer to base class double getconv() { return val2; } l_to_g lgob(4); double getinit() { return val1; } f_to_c fcob(70); virtual void compute() = 0; // use virtual function mechanism to convert }; p = &lgob; cout << p->getinit() << " liters is "; // Liters to gallons. p->compute(); class l_to_g : public convert { cout << p->getconv() << " gallons\n"; // l_to_g public: p = &fcob; l_to_g(double i) : convert(i) { } cout << p->getinit() << " in Fahrenheit is "; void compute() { p->compute(); val2 = val1 / 3.7854; cout << p->getconv() << " Celsius\n"; // f_to_c } return 0; }; }