JLW
JLW

Reputation: 64

Calling overridden function and using overloaded variable from base class

I have two base classes and derivered versions that overload / override certain parts like this:

class base
{
public:
    int X = 1;
};

class deriv : public base
{
public:
    int X = 2;
};

class A
{
public:
    base K;
    virtual void doSmth()
    {
        std::cout << "A" << std::endl;
        smthElse();
    }

    virtual void smthElse()
    {
        std::cout << K.X << std::endl;
    }
};

class B : public A
{
public:
    deriv K;
    void doSmth()
    {
        std::cout << "B" << std::endl;
        smthElse();
    }
};

the application looks like this

int main()
{
    A instanceA;
    B instanceB;

    instanceA.doSmth();
    instanceB.doSmth();

    getchar();
    return 0;
}

And the output therefore is X=1 for both instances A and B. I was wondering why that is. A uses base (X=1) and B uses deriv (X=2). deriv overloads X and B overloads K. Is this because the function smthElse() is only defined in A, thus A can't know about the existance of the overloaded variable K?

If so, is there a way for the function smthElse() to use the overloaded variable K? I found the using keyword but also adding a using A::smthElse; in B won't change the behaviour of X not being printed as 2. The only way I can achieve this is by copying the function smthElse() from A and insert it into B. Is there a different way to achieve what I'm looking for? Since it seems like an overkill to copy'n'paste the same function into B just to use an overridden variable.

Thanks in advance!

Upvotes: 0

Views: 52

Answers (2)

R Sahu
R Sahu

Reputation: 206577

instanceB has two variables named K, A::K and B::K. However, the base class, A, only knows about one K, A::K.

That explains the output.

If so, is there a way for the function smthElse() to use the overloaded variable K?

Yes, you can do that by adding a virtual function in A that returns a reference to base and adding a virtual function in base that returns a reference to i.

class base
{
public:
    int& getX( return X;}
private: 
    int X = 1;
};

class deriv : public base
{
public:
    int& getX( return X;}
private: 
    int X = 2;
};

class A
{
public:
    base& getK() { return K; }
    virtual void doSmth()
    {
        std::cout << "A" << std::endl;
        smthElse();
    }

    virtual void smthElse()
    {
        std::cout << getK().getX() << std::endl;
        //           ^^^^^^^^^^^^^ use the virtual functions
    }
public:
    base K;
};

class B : public A
{
public:
    deriv& getK(){ return K; }
    void doSmth()
    {
        std::cout << "B" << std::endl;
        smthElse();
    }
public:
    base K;
};

PS I hope this is just curiosity and you don't write production code with such style. You will end up confusing yourself and anybody who tries to understand your code.

Upvotes: 2

YSC
YSC

Reputation: 40070

When you write

virtual void smthElse()
{
    std::cout << K.X << std::endl;
}
  • smthElse is virtual
  • K is not (a member variable could not be virtual: it has no meaning for an attribute).

In other terms, it means that B::smthElse will ovevrride A::smthElse but B::K and A::K are two distinct, unrelated and independent variables.

When smthElse is called in the context of a B, K still means A::K.

As a solution, you might create a virtual accessor to Ks:

class base { ...};
class deriv{ ...};

class A
{
    base K;
public:
    virtual const base& theK() { return K; }
    virtual void smthElse() { std::cout << theK().X << "\n"; }
};

class B : public A
{
    deriv K;
public:
    virtual const base& theK() { return K; }
};

When B{}.smthElse() is called, it will call B::theK() which will return B::K (a deriv instance).

Upvotes: 0

Related Questions