QFi
QFi

Reputation: 291

Base and derived classes C++

A few days ago, I wanted to dive into the C++ world. I'm studying the base and derived class concepts. Could someone explain the nuance going on with the following two code snippets?

class A
{
    private:
    virtual int GetValue() { return 10; }

    public:
    int Calculate() { return GetValue()*1.5; }
};

class B: public A
{
    private:
    virtual int GetValue() { return 20; }
};

int main()
{
    B b;
    std::cout << b.Calculate() << std::endl;

    return 0;
}

The output is 30 but 15 was expected

class A
{
    private:
    int m_data;

    public:
    A(): m_data(GetValue()) {}
    int Calculate() { return m_data*1.5; }
    virtual int GetValue() { return 10; }
};

class B: public A
{
    public:
    virtual int GetValue() { return 20; }
};

int main()
{
    B b; A* ap;
    ap=&b; 
    std::cout << ap->Calculate() << std::endl;

    return 0;
}

The output is 15 but 30 was expected

Can someone explain and help me understand the reasoning? Something is wrong with my thinking on this concept, but I am unable to figure it out.

Upvotes: 8

Views: 508

Answers (2)

izlin
izlin

Reputation: 2138

Try the following code for the second example:

class A
{
private:
int m_data;

public:
A(): m_data(GetValue()) { std::cout << "Init m_data and A ";}
int Calculate() { return m_data*1.5; }
virtual int GetValue() { std::cout << "GetValue from A ";return 10; }
};

class B: public A
{
public:
B() { std::cout << "Init B "; }
virtual int GetValue() { std::cout << "GetValue from B"; return 20; }
};

int main()
{
B b; A* ap;
ap=&b; 
std::cout << ap->Calculate() << std::endl;

return 0;
}

It is the same as you already have but with outputs. You should get GetValue from A Init m_data and A Init B 15. I hope now you see why you have an output of 15. With the outputs you should be able to reconstruct the execution order.

Upvotes: 2

Bathsheba
Bathsheba

Reputation: 234635

First case:

This is trivial. You have an instantiated instance of B, and you compute return GetValue() * 1.5; which uses B::GetValue() as you've marked GetValue() to be virtual in the base class. Hence 20 * 1.5 is evaluated.

Second case:

Not so trivial. You are calling GetValue() in the base member initialiser to set a value for m_data. Standard C++ dictates that the base class GetValue() method will be called in that case. (Informally think of this as being due to class B not being constructed until class A is fully constructed). Hence 10 * 1.5 is evaluated. Interestingly, if GetValue() was pure virtual, then the behaviour of the program would have been undefined.


Reference: Why a virtual call to a pure virtual function from a constructor is UB and a call to a non-pure virtual function is allowed by the Standard?

Upvotes: 5

Related Questions