CHAPTER 15

image

Overriding

A new method in a derived class can redefine a method in a base class in order to give it a new implementation.

Hiding Derived Members

In the example below, Rectangle’s getArea method is redeclared in Triangle with the same signature. The signature includes the name, parameter list and return type of the method.

class Rectangle
{
 public:
  int x, y;
  int getArea() { return x * y; }
};

class Triangle : public Rectangle
{
 public:
  Triangle(int a, int b) { x = a; y = b; }
  int getArea() { return x * y / 2; }
};

If a Triangle object is created and the getArea method is invoked, then Triangle’s version of the method will get called.

Triangle t = Triangle(2,3);
t.getArea(); // 3 (2*3/2) calls Triangle’s version

However, if the Triangle is upcast to a Rectangle then Rectangle’s version will get called instead.

Rectangle& r = t;
r.getArea(); // 6 (2*3) calls Rectangle’s version

That is because the redefined method has only hidden the inherited method. This means that Triangle’s implementation is redefined downwards in the class hierarchy to any child classes of Triangle, but not upwards to the base class.

Overriding Derived Members

In order to redefine a method upwards in the class hierarchy – what is called overriding – the method needs to be declared with the virtual modifier in the base class. This modifier allows the method to be overridden in derived classes.

class Rectangle
{
 public:
  int x, y;
  virtual int getArea() { return x * y; }
};

Calling the getArea method from Rectangle’s interface will now invoke Triangle’s implementation.

Rectangle& r = t;
r.getArea(); // 3 (2*3/2) calls Triangle’s version

C++11 added the override specifier, which indicates that a method is intended to replace an inherited method. Using this specifier allows the compiler to check that there is a virtual method with that same signature. This prevents the possibility of accidentally creating a new virtual method.

virtual float getArea() override {} // error - no base class method to override

Another specifier introduced in C++11 is final. This specifier prevents a virtual method from being overridden in derived classes. It also prevents derived classes from using that same method signature.

class Base
{
  virtual void foo() final {}
}

class Derived
{
  void foo() {} // error: Base::foo marked as final
}

The final specifier can also be applied to a class to prevent any class from inheriting it.

class B final {}
class D : B {} // error: B marked as final

Base Class Scoping

It is still possible to access a redefined method from a derived class by typing the class name followed by the scope resolution operator. This is called base class scoping and can be used to allow access to redefined methods that are any number of levels deep in the class hierarchy.

class Triangle : public Rectangle
{
 public:
  Triangle(int a, int b) { x = a; y = b; }
  int getArea() { return Rectangle::getArea() / 2; }
};
..................Content has been hidden....................

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