Overriding Functions

A Dog object has access to all the member functions in class Mammal, as well as to any member functions, such as WagTail(), that the declaration of the Dog class might add. It can also override a base class function. Overriding a function means changing the implementation of a base class function in a derived class. When you make an object of the derived class, the correct function is called.

When a derived class creates a member function with the same return type and signature as a member function in the base class, but with a new implementation, it is said to be overriding that method.


When you override a function, it must agree in return type and in signature with the function in the base class. The signature is the function prototype other than the return type: that is, the name, the parameter list, and the keyword const, if used.

The signature of a function is its name, as well as the number and type of its parameters. The signature does not include the return type.


Listing 16.5 illustrates what happens if the Dog class overrides the speak() method in Mammal. To save room, the accessor functions have been left out of these classes.

Listing 16.5. Overriding a Base Class Method in a Derived Class
 0:  //Listing 16.5 Overriding a base class method in a derived class
 1:  #include <iostream>
 2:
 3:  enum BREED { YORKIE, CAIRN, DANDIE, SHETLAND, DOBERMAN, LAB };
 4:
 5:  class Mammal
 6:  {
 7:  public:
 8:      // constructors
 9:      Mammal() { std::cout << "Mammal constructor...
"; }
10:      ~Mammal() { std::cout << "Mammal destructor...
"; }
11:
12:      //Other methods
13:      void Speak()const { std::cout << "Mammal sound!
"; }
14:      void Sleep()const { std::cout << "shhh. I'm sleeping.
"; }
15:
16:  protected:
17:      int itsAge;
18:      int itsWeight;
19:  };
20:
21:  class Dog : public Mammal
22:  {
23:  public:
24:      // Constructors
25:      Dog(){ std::cout << "Dog constructor...
"; }
26:      ~Dog(){ std::cout << "Dog destructor...
"; }
27:
28:      // Other methods
29:      void WagTail() { std::cout << "Tail wagging...
"; }
30:      void BegForFood() { std::cout << "Begging for food...
"; }
31:      void Speak()const { std::cout << "Woof!
"; }
32:
33:  private:
34:      BREED itsBreed;
35:  };
36:
37:  int main()
38:  {
39:      Mammal bigAnimal;
40:      Dog fido;
41:      bigAnimal.Speak();
42:      fido.Speak();
43:      return 0;
44:  }


Mammal constructor...
Mammal constructor...
Dog constructor...
Mammal sound!
Woof!
Dog destructor...
Mammal destructor...
Mammal destructor...
					

On line 31, the Dog class overrides the Speak() method, causing Dog objects to say Woof! when the Speak() method is called. On line 39, a Mammal object, bigAnimal, is created, causing the first line of output when the Mammal constructor is called. On line 40, a Dog object, fido, is created, causing the next two lines of output, where the Mammal constructor and then the Dog constructor are called.


On line 41, the Mammal object calls its Speak() method; then on line 42 the Dog object calls its Speak() method. The output reflects that the correct methods were called. Finally, the two objects go out of scope, and the destructors are called.

Overloading Versus Overriding

These terms are similar, and they do similar things. When you overload a method, you create more than one method with the same name but with different signatures. When you override a method, you create a method in a derived class with the same name as a method in the base class and with the same signature.

Hiding the Base Class Method

In the previous listing, the Dog class's method Speak() hides the base class's method. This is just what is wanted, but it can have unexpected results. If Mammal has a Move() method that is overloaded, and Dog overrides that method, the Dog method will hide all the Mammal methods with that name.

If Mammal overloads Move() as three methods—one that takes no parameters, one that takes an integer, and one that takes an integer and a direction—and Dog overrides just the Move() method, which takes no parameters, it will not be easy to access the other two methods using a Dog object. Listing 16.6 illustrates this problem.

Listing 16.6. Hiding Methods
 0:  //Listing 16.6 Hiding methods
 1:
 2:  #include <iostream>
 3:
 4:  class Mammal
 5:  {
 6:  public:
 7:      void Move() const { std::cout << "Mammal move one step
"; }
 8:      void Move(int distance) const
 9:          { std::cout << "Mammal move " << distance <<" steps.
"; }
10:  protected:
11:      int itsAge;
12:      int itsWeight;
13:  };
14:
15:  class Dog : public Mammal
16:  {
17:  public:
18:      void Move() const { std::cout << "Dog move 5 steps.
"; }
19:  }; // You may receive a warning that you are hiding a function!
20:
21:  int main()
22:  {
23:      Mammal bigAnimal;
24:      Dog fido;
25:      bigAnimal.Move();
26:      bigAnimal.Move(2);
27:      fido.Move();
28:      // fido.Move(10);
29:      return 0;
30:  }


Mammal move one step
Mammal move 2 steps
Dog move 5 steps
						

All the extra methods and data have been removed from these classes. On lines 7 and 8, the Mammal class declares the overloaded Move() methods. On line 18, Dog overrides the version of Move() with no parameters. These are invoked on lines 25–27, and the output reflects this as executed.


Line 28, however, is commented out, as it causes a compile-time error. Although the Dog class could have called the Move(int) method if it had not overridden the version of Move() without parameters, now that it has done so it must override both if it wants to use both. This is reminiscent of the rule that states if you supply any constructor, the compiler will no longer supply a default constructor.

It is a common mistake to hide a base class method, when you intend to override it, by forgetting to include the keyword const. const is part of the signature, and leaving it off changes the signature and thus hides the method rather than overriding it.

Calling the Base Method

If you have overridden the base method, it is still possible to call it by fully qualifying the name of the method. You do this by writing the base name, followed by two colons and then the method name. For example:

Mammal::Move()

It would have been possible to rewrite line 28 in Listing 16.6 so that it would compile:

28:     fido.Mammal::Move(10);

This calls the Mammal method explicitly. Listing 16.7 fully illustrates this idea.

Listing 16.7. Calling the Base Method from the Overridden Method
 0:  //Listing 16.7 Calling base method from overridden method.
 1:  #include <iostream>
 2:
 3:  class Mammal
 4:  {
 5:  public:
 6:      void Move() const { std::cout << "Mammal move one step
"; }
 7:      void Move(int distance) const
 8:          { std::cout << "Mammal move "
 9:                << distance << " steps.
"; }
10:  protected:
11:      int itsAge;
12:      int itsWeight;
13:  };
14:
15:  class Dog : public Mammal
16:  {
17:  public:
18:      void Move()const;
19:  };
20:
21:  void Dog::Move() const
22:  {
23:      std::cout << "In dog move...
";
24:      Mammal::Move(3);
25:  }
26:
27:  int main()
28:  {
29:      Mammal bigAnimal;
30:      Dog fido;
31:      bigAnimal.Move(2);
32:      fido.Mammal::Move(6);
33:      return 0;
34:  }


Mammal move 2_steps
Mammal move 6_steps
						

On line 29, a Mammal, bigAnimal, is created; and on line 30, a Dog, Fido, is created. The method call on line 31 invokes the Move() method of Mammal, which takes an int.


The programmer wants to invoke Move(int) on the Dog object, but has a problem. Dog overrides the Move() method, but does not overload it and does not provide a version that takes an int. This is solved by the explicit call to the base class Move(int) method on line 32.

DO extend the functionality of tested classes by deriving.
DO change the behavior of certain functions in the derived class by overriding the base class methods.
DON'T hide a base class function by changing the function signature.


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.16.48.181