user1110728
user1110728

Reputation: 113

C++ - Dynamic Binding and Object Instances Not Accessing Derived Methods

I haven't written anything in C++ in quite some time, and am running into some inheritance issues that are confusing.

First question - From my understanding, a base class with a virtual method whose derived class implements that method should call the derived method IF the method is called from a pointer to the base class. Why does it need to be a pointer? Is this because of the way vtables are implemented? If so, why is an implementation detail not abstracted in the actual specification? I am trying to understand why this is the case. Is there a time when you want the base class to be called, only if the object is not a pointer? I thought the point was for pointers to objects to behave similarly to those objects.

Second question - In the below code, I ran a test to see that derived class methods were called if the method of access was a pointer. Then, I went back and tried to use the same method to turn the instance into a pointer to achieve the same binding. However, there is no cast that will allow me to use the class as a derived class if it was, at any point, stored as an object instance. Why is this? If, for example, I took the same objects (further below) and put them in a vector then it works correctly.

    #include <iostream>
    #include <string>
    #include <vector>
    using namespace std;

    class BaseClass {
    public:
        virtual void A();
        virtual void B();
    };

    void BaseClass::A() {
        cout << "In base A" << endl;
    }

    void BaseClass::B() {
        cout << "In base B" << endl;
    }

    class DerivedClass1 : public BaseClass {
    public:
        void A();
        void B();
    };

    void DerivedClass1::A() {
        cout << "In Derived A" << endl;    
    }

    void DerivedClass1::B() {
        cout << "In Derived B" << endl;
    }

    int main(int argc, char** argv) {    
        string cmd;
        BaseClass bc;
        DerivedClass1 dc1;    

        vector<BaseClass> list;
        list.push_back(bc);
        list.push_back(dc1);    

        cout << "Calling by " << endl;
        for(int i = 0; i < list.size(); i++) {  
            // There is no possible cast to BaseClass* that causes A or B to call the derived class
            (dynamic_cast<BaseClass*>(&list[i]))->A();
            (dynamic_cast<BaseClass*>(&list[i]))->B();
        }


        // However, the below code, although it stores the same addresses, etc. works fine.
        vector<BaseClass*> list_ptrs;    
        list_ptrs.push_back(&bc);
        list_ptrs.push_back(&dc1);    

        cout << "Outputting Pointers" << endl;
        for(int i = 0; i < list_ptrs.size(); i++) {    
            list_ptrs[i]->A();
            list_ptrs[i]->B();
        }

        getline(cin, cmd);
    }

Sorry if I am just misunderstanding something very basic, but it seems to be an inconsistency in the way that dynamic binding works, and I can't find a decent explanation (all Google returns are people trying to access base class methods...).

Any assistance would be appreciated, Thanks, -Alex

Upvotes: 1

Views: 308

Answers (1)

PaulMcKenzie
PaulMcKenzie

Reputation: 35455

This is wrong:

    BaseClass bc;
    DerivedClass1 dc1;    

    vector<BaseClass> list;
    list.push_back(bc);
    list.push_back(dc1);    

Your vector can only store BaseClass objects. Trying to stuff a DerivedClass into something that can only hold BaseClass objects is termed as object slicing, which you do not want happen. Object slicing means just that -- you are "slicing off" the DerivedClass's attributes so that it is a BaseClass.

Either have a vector of BaseClass pointers, or two separate vectors, one of BaseClass objects, the other of DerivedClass objects.

vector<BaseClass*> theList;
theList.push_back(&bc);
theList.push_back(&dc1);

You should now see the virtual functions work as expected.

Upvotes: 4

Related Questions