virtual functions allow derived classes to provide different versions of a base class function. You can use the virtual keyword to declare a virtual function in a base class. By declaring the function prototype in the usual way and then prefixing the declaration with the virtual keyword. To declare a pure function (which automatically declares an abstract class), prefix the prototype with the virtual keyword, and set the function equal to zero.
virtual int funct1(void); // A virtual function declaration. virtual int funct2(void) = 0; // A pure function declaration.
A function declaration cannot provide both a pure-specifier and a definition.
struct C { virtual void f() { } = 0; // ill-formed };
The only legal syntax to provide a body is:
struct TheClass { virtual void funct3(void) = 0; }; virtual void TheClass::funct3(void) { // Some code here. };
To redefine a virtual function in any derived class, the number and type of arguments must be the same in the base class declaration and in the derived class declaration. (The case for redefined virtual functions differing only in return type is discussed below.) A redefined function is said to override the base class function.
You can also declare the functions int Base::Fun(int) and int Derived::Fun(int) even when they are not virtual. In such a case, int Derived::Fun(int) is said to hide any other versions of Fun(int) that exist in any base classes. In addition, if class Derived defines other versions of Fun(), (that is, versions of Fun() with different signatures) such versions are said to be overloaded versions of Fun().
Virtual function return types
Generally, when redefining a virtual function, you cannot change just the function return type. To redefine a virtual function, the new definition (in some derived class) must exactly match the return type and formal parameters of the initial declaration. If two functions with the same name have different formal parameters, C++ considers them different, and the virtual function mechanism is ignored.
However, for certain virtual functions in a base class, their overriding version in a derived class can have a return type that is different from the overridden function. This is possible only when both of the following conditions are met:
struct X {};// Base class. struct Y : X {};// Derived class. struct B { virtual void vf1(); virtual void vf2(); virtual void vf3(); void f(); virtual X* pf();// Return type is a pointer to base. This can // be overridden. }; class D : public B { public: virtual void vf1();// Virtual specifier is legal but redundant. void vf2(int);// Not virtual, since it's using a different // arg list. This hides B::vf2(). // char vf3();// Illegal: return-type-only change! void f(); Y* pf();// Overriding function differs only // in return type. Returns a pointer to // the derived class. }; void extf() { D d;// Instantiate D B* bp = &d;// Standard conversion from D* to B* // Initialize bp with the table of functions // provided for object d. If there is no entry for a // function in the d-table, use the function // in the B-table. bp–>vf1(); // Calls D::vf1 bp–>vf2(); // Calls B::vf2 since D's vf2 has different args bp–>f(); // Calls B::f (not virtual) X* xptr = bp–>pf();// Calls D::pf() and converts the result // to a pointer to X. D* dptr = &d; Y* yptr = dptr–>pf();// Calls D::pf() and initializes yptr. // No further conversion is done. }
The overriding function vf1 in D is automatically virtual. The virtual specifier can be used with an overriding function declaration in the derived class. If other classes will be derived from D, the virtual keyword is required. If no further classes will be derived from D, the use of virtual is redundant.
The interpretation of a virtual function call depends on the type of the object it is called for; with nonvirtual function calls, the interpretation depends only on the type of the pointer or reference denoting the object it is called for.
virtual functions exact a price for their versatility: each object in the derived class needs to carry a pointer to a table of functions in order to select the correct one at runtime (late binding).
Copyright(C) 2009 Embarcadero Technologies, Inc. All Rights Reserved.
|
What do you think about this topic? Send feedback!
|