Aller au contenu

Class Inheritance

Inheritance Syntax

Inheritance in C++ is implemented by adding the list of inheritances after the class name followed by a :. For making the public members of the base class accessible as public members of the derived class, the inheritance must be declared public.

Multiple vs. Single Inheritance

Unlike in Java, a class in C++ can inherit from multiple classes (multiple inheritance vs. single inheritance).

Inheritance vs. Interface Implementation

Unlike Java, C++ does not distinguish between inheritance and interface implementation. In Java, a class can only inherit from one class (using the extends keyword) but it can implement several interfaces (using the implements keyword). In C++, both concepts are implemented using inheritance. Interfaces are usually declared as classes that contain only pure virtual methods. Virtual and pure virtual methods are explained in a following task.

Base Class Constructors

In Java, the keyword super is used to call the base constructor. In C++, base class constructors are automatically called for you if they have no argument. To call a superclass constructor with an argument, the initialization list must be used. This is illustrated in the Base2 and Derived classes.

Polymorphism

C++ supports virtual methods and pure virtual methods for implementing polymorphic behavior, similar to Java’s interfaces and abstract methods.

example

#include <iostream>

class Base1 {
public:
    Base1() {
        std::cout << "Base1 constructor" << std::endl;
    }
};

class Base2 {
public:
    Base2() {
        std::cout << "Base2 default constructor" << std::endl;
    }
    Base2(int x) {
        std::cout << "Base2 constructor" << std::endl;
    }
};

class Derived : public Base1, Base2 {
public:
    Derived(int x) : Base2(x) {
        std::cout << "Derived constructor" << std::endl;
    }
};

int main() {
    Derived d(2);  // The Derived class extends Base1 and Base2
    return 0;
}

Virtual Method

Virtual methods are member methods whose behavior can be overridden in derived classes. As opposed to non-virtual methods, the overriding behavior is preserved even if there is no compile-time information about the actual type of the class. This is illustrated by the main.cpp file.

If you run the program snippet, you should observe that the expected methods are called. You may then modify this program by removing the virtual modifier keyword from the Base class and the override keyword from the Derived class. You should then observe that in all cases the f() method from the declared type is called.

Note that the use of the override keyword is optional. It is however very useful for identifying method redefinition errors at compile time, since it indicates to the compiler that a specific method is a method that is redefined in the derived class.

Without going to more details, one may say that virtual methods are like any non final methods in Java. The method that is effectively called is the one of the run-time type of the object (and not the one of the declared type) . From this perspective, polymorphism is existing in both C++ and Java.

#include <iostream>

class Base {
public:
    virtual void f() {
        std::cout << "f() in Base class called" << std::endl;
    }
};

class Derived : public Base {
public:
    void f() override { // 'override' keyword is optional
        std::cout << "f() in Derived class called" << std::endl;
    }
};

int main() {
    Base b;     // Create a base instance
    Derived d;  // Create a derived instance
    b.f();      // Prints base
    d.f();      // Prints derived

    // Virtual method call through reference
    Base& br = b;   // The type of br is Base&
    Base& dr = d;   // The type of dr is Base& as well
    br.f();         // Prints base
    dr.f();         // Prints derived (because Base::f() is declared as virtual)

    // Virtual method call through pointer
    Base* bp = &b;  // The type of bp is Base*
    Base* dp = &d;  // The type of dp is Base* as well
    bp->f();        // Prints base
    dp->f();        // Prints derived (because Base::f() is declared as virtual)

    // Non-virtual method calls
    br.Base::f();   // prints base
    dr.Base::f();   // prints base

    return 0;
}

Pure Virtual Method

A pure virtual method is a virtual method that has the following syntax: virtual method_declaration = 0;. A pure virtual method cannot have any definition (so it does not have a body).

An abstract class is a class that either defines or inherits one or more pure virtual methods. Abstract classes cannot be instantiated - no object of an abstract class can be created.

This mechanism is often used in C++ for defining classes that act as interfaces. Such classes are similar to interfaces in Java and are used for representing concepts in a way that is separated from implementation of the concept. Using abstract classes is always through reference or pointer - since no instantiation of an abstract class is possible. An instance of a class that inherits from an abstract class can be casted to the abstract class reference or pointer. This is also illustrated in the given program snippet.

#include <iostream>

class Abstract {
public:
    // Virtual method
    virtual void m1() {
        std::cout << "m1 in Abstract class called" << std::endl;
    }
    // Pure virtual method
    virtual void m2() = 0;
};

class Concrete : public Abstract {
public:
    // Override of the pure virtual method
    void m2() override { // 'override' is optional
        std::cout << "m2 in Concrete class called" << std::endl;
    }
};

int main() {
    // It is not possible to create an instance of Abstract
    // Abstract a;
    Concrete c;

    // Virtual method call through reference
    c.m1(); // prints Abstract
    c.m2(); // prints Concrete

    // C can be viewed as a reference to the Abstract class
    Abstract& a1 = c;
    a1.m1(); // prints Abstract
    a1.m2(); // prints Concrete

    return 0;
}