0

I was reading this. It says that

Some people believe that the purpose of inheritance is code reuse. In C++, this is wrong. Stated plainly, “inheritance is not for code reuse.

The purpose of inheritance in C++ is to express interface compliance (subtyping), not to get code reuse. In C++, code reuse usually comes via composition rather than via inheritance. In other words, inheritance is mainly a specification technique rather than an implementation technique.

So, my question is what exactly interface compliance(subtyping) in C++? How inheritance is used to express it? How subtyping & subclasses are different? It would be better if someone answers it by giving suitable real world example.

1

Rather than having a reusable code, you have a code which is interchangeable.

A real life example using the DI and Adapter patters. Let's say you have a class, which handles data. It does not retrieve the data, but handles it. We could simply call it DataHandler.

class DataHandler
{
public:
    void doSomethingWithData() {}
protected:
private:
};

When you start using the DataHandler in your app, you use it to handle data from a SQL Database. So the DataHandler will need an instance of said class.

class SqlDatabaseDataRetriever
{
public:
    Data getData() { }
protected:
private:
};

class DataHandler
{
public:
    DataHandler(SqlDatabaseDataRetriever& dataRetriever)
    {
        _dataRetriever = dataRetriever;
    }

    void doSomethingWithData()
    {
        Data data = this->_dataRetriever.getData();
    }
protected:
    SqlDatabaseDataRetriever _dataRetriever;
private:
};

But what if later you decide, you don't want to access the database directly via SqlDatabaseDataRetriever, so you create an API and you create new class which is used to handle the request via your API and retrieves data from it.

So we want to use the DataHandler class with our new ApiDataRetriever, but currently our DataHandler uses a different class. You could just rewrite your code, inject the ApiDataRetriever instead, but there's a better solution.

You will create an abstract class, which all your DataRetrievers will inherit, you will inject this abstract class instead and use it's methods.

class DataRetriever
{
public:
    virtual Data getData() = 0;
protected:
private;
}

class SqlDatabaseDataRetriever : public DataRetriever
{
public:
    virtual Data getData() { }
protected:
private;
}

class ApiDataRetriever : public DataRetriever
{
public:
    virtual Data getData() { }
protected:
private;
}

class DataHandler
{
public:
    DataHandler(DataRetriever& dataRetriever)
    {
        _dataRetriever = dataRetriever;
    }

    void doSomethingWithData()
    {
        Data data = this->_dataRetriever.getData();
    }
protected:
    DataRetriever _dataRetriever;
private:
};

Because the function in parent class is defined as pure virtual, it has to be implemented in child class, and because you are injecting the parent class, but that cannot be instantiated, you will always get a subject class having the parent method, which you can use without constraints.

1

A subtype is a type which fulfills the contract of a basetype.

A subclass is a class which inherits from a baseclass.

In C++ (disregarding templates) you can only create a subtype by subclassing, which gives the compiler lots of additional information useful for optimization and static checking.
The same cannot be said about objective-c, where a subtype only needs to handle the messages the basetype understands the same way: Duck-typing "If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck."
C++ templates are also duck-typing (types must have appropriate members), though completely at compile-time and thus not incurring any of the penalties of dynamic typing.


An example of sub-typing without sub-classing would be using standard algorithms:

template<class T> void sortall(T& x) {
    using std::begin;
    using std::end;
    std::sort(begin(v), end(v));
}

Which can be called whether the argument is a std::vector, a std::array or some other container, even though none of the examples are related by inheritance.

While sub-classing without sub-typing is possible by ignoring the inherited contract, that's a sin one simply should abstain from committing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.