VextoR
VextoR

Reputation: 5165

How to call function from inherited class?

I have the code:

class A{ //base class
public:
    virtual std::string getString(){return "class A";}
};

class B: public A{
public:
    std::string getString() {return "it is B class";}
};

class C{
public:
    C(){
        B b;
        a = b;
    }
    std::string test() {return a.getString();}
private:
    A a;
};


int main()
{
    C c;
    std::cout << c.test();

    return 0;
}

c.test() says "class A", but how I can call method getString() from class B and not A?

Thanks!

Upvotes: 1

Views: 635

Answers (4)

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361472

You need to implement like this:

class C{
public:
    C(){
        a = new B;
    }
    std::string test() {return a->getString();}
private:
    A *a;
};

This will call getString() from class B and not A.

What you're trying to do is called "dynamic polymorphism" which is achieved through pointer (or reference) of type base class (which is A), but the pointer points to an object of type derived class (which is B).

Upvotes: 5

P&#233;ter T&#246;r&#246;k
P&#233;ter T&#246;r&#246;k

Reputation: 116266

The problem is, your B object gets sliced when assigned to an A object. This is because you assigned by value, not by reference or pointer. Since you declared a like this

A a;

what happens during the assignment a = b is that the actual state of b is copied over into a. However, since a is a value object, only the A part of object b is copied, and its "B-ness" is completely lost!

To avoid this, you need to declare a as a pointer type, as suggested by others (a reference would also work, but then you would need to considerably rewrite your example, since you can't assign to references, only initialize them). If a is a pointer (A*), the assignment a = b makes a point to the object represented by b, which is still a B object, thus you will observe the polymorphic behaviour you expected. However, in this case, you must ensure that b stays alive even after exiting the constructor - otherwise you leave a dangling reference which causes undefined behaviour (read: bad things you don't want to happen) when dereferenced.

Since a pointer example was already shown by @Nawaz, I will give another using a reference:

class C{
public:
    C() : a(b) { // references must be initialized in the constructor initializer list
    }
    std::string test() {return a.getString();}
private:
    B b; // moved to class scope to ensure that it stays alive
    A& a;
};

Upvotes: 7

CashCow
CashCow

Reputation: 31445

You are slicing therefore it will not work. a is an A it is not a B.

To work your class member variable a must be a pointer or a reference.

As a pointer

class C{
public:
    C(){
        a = new B;
    }
    std::string test() {return a->getString();}
private:
    A *a;
};

As a reference

class C{
    public:
        C() : a( *(new B) )
        {
        }
        std::string test() {return a.getString();}
    private:
        A &a;
    };

Of course the code I have produced leaks but will work with the virtual function.

Upvotes: 1

zweihander
zweihander

Reputation: 6295

Because your member a is not an A*, it is an A instance. Therefore you are just assigning the A part of B to variable a. if you convert a to an A*, you will get the expected result.

Upvotes: 1

Related Questions