Home > Mobile >  Unexpected behaviour when using inheritance
Unexpected behaviour when using inheritance

Time:09-23

I have a Base class, which is then inherited by Foo, and Foo is in turn inehrited by Bar.

Here is the header file base.h for my Base class:

#pragma once

class Base {
    public:
        void runExample();

    private:
        virtual void print();
};

And the implementation base.cpp:

#include "base.h"

void Base::runExample() {
    print();
}

void Base::print() {};

Here is the header file foo.h for my Foo class:

#pragma once
#include "../base/base.h"

class Foo : public Base {
    public:
        Foo();

    private:
        void print();

        const char* toPrint;
};

And the implementation foo.cpp:

#include "foo.h"

Foo::Foo() {
    toPrint = "Hello Foo";
}

void Foo::print() {
    std::cout << toPrint << std::endl;
}

Here is the header file bar.h for my Bar class:

#pragma once
#include "../foo/foo.h"

class Bar : public Foo {
    public:
        Bar();

    private:
        const char* toPrint; // "overrides" toPrint from parent class Foo?
};

And the implementation bar.cpp:

#include "bar.h"

Bar::Bar() {
    toPrint = "Hello Bar";
}

And finally, my main function:

#include "../bar/bar.h"
int main() {
    Bar bar = Bar();
    bar.runExample();
}

So, I have this kind of relationship between the classes:

Bar is a Foo which is a Base.

What I was expecting to see in the output was "Hello Bar", but what I actually see is "Hello Foo".

If I "override" the print method declared in Foo in Bar to print toPrint then I get the expected result, however this seems to break the point of inheritance; i.e. why would I need to re-define the functionality when it's already defined.

What I am expecting is that when Bar.print() is invoked, it uses Foos implementation, but the actual field toPrint has been "replaced" with the value inside the Bar implementation.

I am very new to C , and I'm coming from a Kotlin background. Forgive me if this is like C 101 basics, but I'm pretty confused as to why this is happening. Could anyone point me in the right direction?

CodePudding user response:

In C , data members cannot be "overridden" as you expect, and a reference to toPrint will not be dynamically bound to equally named data members in subclasses.

With

class Bar : public Foo {
        ...
        const char* toPrint; // "overrides" toPrint from parent class Foo?
};

you introduce a member variable Bar::toPrint next to Foo::toPrint, which is inherited. The code

void Foo::print() {
    std::cout << toPrint << std::endl;
}

will always stick to the toPrint-member in his scope, i.e. to Foo::toPrint.

The following code illustrates this behaviour:

struct Base {
    const char* toPrint = "Base";
    virtual void print() const { cout << toPrint << std::endl; }
};

struct Derived: public Base {
    const char* toPrint = "Derived";
    
    void printBoth() const { cout << "own:" << toPrint << "; inherited: " << Base::toPrint << std::endl; }
};

int main() {
    
    Derived d;
    
    cout << "call inherited method print:" << std::endl;
    d.print();
    
    cout << "call method printBoth, showing both data members:" << std::endl;
    d.printBoth();
}

Output:

call inherited method print:
Base
call method printBoth, showing both data members:
own:Derived; inherited: Base
  •  Tags:  
  • c
  • Related