Function Name Hiding: This Is Not Function Overriding

 < Day Day Up > 



Function Name Hiding: This Is Not Function Overriding!

If a derived class function has the same function signature as a base class function, the derived class function hides the base class function. Function hiding is a lot like variable scoping. If you declare a variable in a local scope it will hide a variable with the same name in an enclosing scope. Function hiding only affects inherited public and protected functions since derived classes do not have access and therefore cannot see private base class functions.

Function Hiding vs. Function Overloading

Function hiding differs from function overloading in several ways. There can be several overloaded functions in the same class. One overloaded function differs from another overloaded function in the number and type of its parameters.

A hiding function has the same name and the same number and types of parameters. A hiding function will only appear in a derived class to hide a function with the same signature in its base class.

Another way to think of it is like this: When you overload a class function you are creating multiple versions of a function with the same name. Each different version of the overloaded function must be unique in its parameter list. When you call an overloaded function the compiler determines which overloaded function you’re referring to by what arguments are used to make the function call.

A hiding function appears in a derived class. A hiding function in a derived class hides its matching function in its base class. There is a one-for-one mapping between a base class function and its hiding function in a derived class. Take a look at figure 13-8.


Figure 13-8: Foo and DerivedFoo Class Diagram

Figure 13-8 shows a class diagram for a class named Foo and a subclass of Foo named DerivedFoo. In addition to constructors and destructors each class implements a function named getI(). Notice that the function signature of DerivedFoo::getI() matches that of Foo::getI(). The code for both of these classes is given in examples 13.10 through 13.14 below.

Listing 13.10: foo.h

start example
  1  #ifndef FOO_H  2  #define FOO_H  3  4  class Foo{  5   public:  6       Foo(int _i = 0);  7       virtual ~Foo();  8       int getI();  9   private: 10       int i; 11  }; 12  #endif
end example

Listing 13.11: derivedfoo.h

start example
  1  #ifndef DERIVED_FOO_H  2  #define DERIVED_FOO_H  3  #include "foo.h"  4  5  class DerivedFoo : public Foo{  6   public:  7       DerivedFoo(int _i = 0);  8       virtual ~DerivedFoo();  9       int getI(); 10   private: 11       int i; 12  }; 13  #endif
end example

Listing 13.12: foo.cpp

start example
  1  #include "foo.h"  2  #include <iostream>  3  using namespace std;  4  5  Foo::Foo(int _i):i(_i){  6    cout<<"Foo object created"<<endl;  7  }  8  9  Foo::~Foo(){ 10     cout<<"Foo object destroyed!"<<endl; 11  } 12 13  int Foo::getI(){  14     cout<<"Foo getI(): "; 15     return i; 16  }
end example

Listing 13.13: derivedfoo.cpp

start example
  1  #include "derivedfoo.h"  2  #include <iostream>  3  using namespace std;  4  5  DerivedFoo::DerivedFoo(int _i):Foo(_i), i(_i){  6      cout<<"DerivedFoo object created."<<endl;  7  }  8  9  DerivedFoo::~DerivedFoo(){ 10      cout<<"Derived Foo object destroyed!"<<endl; 11  } 12 13  int DerivedFoo::getI(){ 14      cout<<"DerivedFoo getI():  "; 15      return i; 16  }
end example

Listing 13.14: main.cpp

start example
  1  #include <iostream>  2  using namespace std;   3  #include "foo.h"  4  #include "derivedfoo.h"  5  #include "ddfoo.h"  6  7  int main(){  8       Foo f1(1);  9       cout<<"getI() called on base class object: "<<endl; 10       cout<<f1.getI()<<endl; 11       cout<<"----------------------------------- "<<endl; 12 13       DerivedFoo d1(2); 14       cout<<"getI() called on derived class object: "<<endl; 15       cout<<d1.getI()<<endl; 16       cout<<"----------------------------------- "<<endl; 17 18       Foo* foo_ptr = new DerivedFoo(3); 19       cout<<"getI() called via base class pointer: "<<endl; 20       cout<<foo_ptr->getI()<<endl; 21       cout<<" ----------------------------------- "<<endl; 22 23       DerivedFoo* derived_foo_ptr = new DerivedFoo(4); 24       cout<<"Derived getI() called via derived class pointer: "<<endl; 25       cout<<derived_foo_ptr->getI()<<endl; 26       cout<<" ----------------------------------- "<<endl; 27 28       delete foo_ptr; 29       delete derived_foo_ptr; 30       return 0; 31  }
end example

The important behavior to note here is the result of function calls on different objects. For instance, when the getI() function is invoked on a Foo object, the Foo::getI() is called. This is as you would expect. When getI() is invoked on a DerivedFoo object, the DerivedFoo::getI() is called. This happens because DerivedFoo::getI() hides Foo::getI(). If DerivedFoo did not declare and implement a function named getI() then Foo::getI() would have been called because it was publicly inherited from the Foo class by the DerivedFoo class.

Note the behavior of pointers. On line 18 of example 13.14 a Foo pointer is declared and initialized to the address of a DerivedFoo object. When getI() is called via the base class pointer it results in the base class version of the function being called, as is shown in figure 13-9.

click to expand
Figure 13-9: Results of Running Example 13.14

On line 23 of example 13.14 a DerivedFoo pointer is declared and initialized to the address of a DerivedFoo object. When getI() is called via the derived class pointer it results in DerivedFoo::getI() being called.

I want to revisit the base class pointer topic for a moment. The base class, in this case Foo, published a set of public interface methods. These were its constructor, destructor, and getI(). Disregarding the constructor and destructor, if an implementation of getI() exists in the base class it will be called via the base class pointer even though the pointer points to a derived class object. You can, however, change this behavior by declaring functions to be virtual, using the virtual keyword. I will show you how to do this in the next section.

Quick Review

A function appearing in a derived class having the same function signature of a base class function hides that function. Be careful when dealing with base class pointers. When calling a function via a base class pointer the base class version of the method will be called, even though the base class pointer contains the address of a derived class object, unless the base class function is declared to be virtual.



 < Day Day Up > 



C++ for Artists. The Art, Philosophy, and Science of Object-Oriented Programming
C++ For Artists: The Art, Philosophy, And Science Of Object-Oriented Programming
ISBN: 1932504028
EAN: 2147483647
Year: 2003
Pages: 340
Authors: Rick Miller

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net