Search code examples
c++run-time-polymorphism

Runtime Polymorphism - Arrow operator accessing the wrong member?


I have the following classes in my program:

class base {
public:
    int bval;
    base() {
        bval = 1;
    }
};

class deri: public base {
    int dval;
public:
    deri() {
        dval = 2;
    }
};

And a function f that takes pointer to object of class base and size of array pointed by it:

void f(base *arr, int size) {
    for(int i=0; i<size; i++, arr++){
        cout << arr->bval << " ";
    }
    cout << endl;
}

This is the main:

int main() {
    base a[5];
    f(a, 5); // first call

    deri b[5];
    f(b, 5); // second call
}

The output for first call is 1 1 1 1 1, which is correct.

But the output for second call is 1 2 1 2 1, which is quite unexpected to me. It seems as if the value of dval is getting printed in place of bval for every second iteration of for loop within the function f.

Furthermore, if I include another private data member int dval2 in class deri, the output to second call is 1 2 65535 1 2 every time I execute it (so 65535 doesn't look like any random value).

Why is this behaviour exhibited by arrow operator?


Solution

  • You pass the pointer as a base pointer to f(), so the pointer arithmetic does not fit your deri array.

    At this point: for(int i=0; i<size; i++, arr++), only the size of base is added to arr, because arr is a base pointer.

    It does not matter in this case what type of objects are really stored; they are not looked at when increasing the pointer value.

    Two options that would help:

    1. Use C++ containers. E.g. std::vector<deri> b(5) and void f(const std::vector<deri> &vec).
    2. Pass an array of pointers. In this case, when the pointer is accessed with arrow-operator, polymorphism can take place. Note that your base class needs a vtable, which you will obtain by defining and declaring a virtual destructor (the vtable is not needed to provide the expected output, but for several other reasons).