0

I'm new to OOP programming and C++ (did a little java first), and I came across a problem I do not understand. I basically try to use polymorphism and use the virtual function to call the derived function on the base * I Why does this break when adding the commented line?

#include <iostream>

class Base
{
public:
    Base() { std::cout << "Base constructor.\n"; }
    virtual ~Base() { std::cout << "Base destructor.\n"; }
    virtual void foo() { std::cout << "Base::foo()\n"; }
};

class Derived : public Base
{
    // std::string d_str;
public:
    Derived()  { std::cout << "Derived constructor.\n"; }
    ~Derived() { std::cout << "Derived destructor.\n"; }
    void foo() { std::cout << "Derived::foo()\n"; }
};

int main(int argc, char const *argv[])
{
    Base *ptr = new Derived[3];

    (*ptr).foo();
    (ptr + 1)->foo();
    (ptr + 2)->foo();

    delete[] ptr;
}

It would be great if someone could help me with this!

pekkas
  • 31
  • 5
  • C++ simply can't work that way, if `ptr` wasn't base but the actual type, it would work. Consider the different sizes of different objects and what that means on `ptr + 1`. – Ulrich Eckhardt Dec 14 '19 at 20:37
  • You allocate an array of `Derived` objects, not an array of `Base` objects. With the addition of a new member variable (`d_str`) a `Derived` object is larger than a `Base` object. The array address calculation `ptr + 1` will add the size of `Base` (the compile time known size) to calculate the element's address, not the runtime size of the actual object pointed to. This causes the resulting pointer to be invalid, and dereferencing it (calling a virtual member function) causes Undefined Behavior. – 1201ProgramAlarm Dec 14 '19 at 20:41
  • @UlrichEckhardt thank you, was afraid of this answer! May I ask for some more explanation? I thought that all pointers are always equal size therefore the pointee doesn't matter? How can the program know to call the right function but can't identify the object? – pekkas Dec 14 '19 at 20:41
  • Also note that doing this has undefined behavior whether the `std::string` member is declared or not. It just *seemed* to work without it. – walnut Dec 14 '19 at 20:42
  • @1201ProgramAlarm Ah that makes sense, is there a way to calculate pointers of `base` when we know that it's actually of type `derived`? – pekkas Dec 14 '19 at 20:42
  • @pekkas Just cast it back to `Derived*` before doing the pointer arithmetic. But what would be the point of casting to `Base*` in the first place then? – walnut Dec 14 '19 at 20:43
  • @pekkas All pointers are not equal in size on most platforms, but even if they were (and `Base*` and `Derived*` probably are but `int*` may well be smaller), `Base` and `Derived` are different sizes. So when you do `ptr + 1`, you are adding onto `ptr` the size of one `Base`, which is not right. – David Schwartz Dec 15 '19 at 02:16

0 Answers0