Crashing on calling virtual methods

1.1k Views Asked by At

I read about it in other questions but none of them was similar, some was about to call a virtual method in the constructor, others about pure virtuals, but the question here is about vituais methods that are not pure, but about virtual methods that doesn't need be implemented in all derivatives classes. If the class instantiated doesn't implements the method, if we call, it logically calls the method from the base and it crashes sometimes. I was wondering, why? What is VTABLE (where it enters)? And what is the best way to solve it.

This is a simple example, (avoid answer like pure virtual).

#include <iostream>

class Foo
{
public:
    virtual std::string myString() {}
};

class Bar : public Foo
{
public:
};

int main(int argc, char ** argv)
{
    Foo * bar = new Foo;
    bar->myString();

    return 0;
}

What would be the best solution?

  1. Throw an exception
  2. Using assert(false)
  3. Returning a default value
  4. Avoid implementing a body and it will result in an error in compilation time
  5. None of the alternatives

The best answer will be the one that explains why this happen based on VTABLE and of course, that choose one solution and explain why. The idea is not to base it on opinions.

3

There are 3 best solutions below

3
Peter - Reinstate Monica On BEST ANSWER

The base class does implement the function, it just implements it wrong. It is not related to vtables or anything sophisticated. Solution 4 preferred (since it prevents building wrong programs), if not possible/desired 1 or 2 in that order.

Note that the error is not at all related to virtual functions, or inheritance in general (you do not use Bar, did you notice?). It is not even related to classes at all but would happen with any freestanding function as well. Consider:

#include <iostream>
#include <string>

// Note: UB -- nothing returned
int getInt() {}
std::string getStr() {}

int main(int argc, char ** argv)
{
    // This probably works (read access from an arbitrary 
    // location on the stack which is in the prog's address space)
    std::cout << getInt() << std::endl;

    // This will crash. operator<< will try to access memory through
    // a pointer value which is some arbitrary byte pattern on the stack.
    // Probably not in the prog's address space.
    // Then the destructor for the temporary string will 
    // try to delete the same 
    // memory which will crash in any case, even if it happens to
    // point to valid memory (which, alas, was never allocated).
    std::cout << getStr();

    std::cout << "Still alive?\n"; // never printed
    std::cout.flush();

    return 0;
}

In order to prevent the error from happening with your original code, just return a value. If you implement the function and don't throw or abort (which are the three alternatives), i.e. if you return, you must return a value:

#include <iostream>

class Foo
{
public:
    virtual std::string myString() { return "test\n";}
};

class Bar : public Foo
{
public:
};

int main(int argc, char ** argv)
{
    Foo * bar = new Foo();
    std::cout << bar->myString();

    return 0;
}
4
Shashish Chandra On

Your mystring function should return a string.

0
Logicrat On

The VTABLE is a table of pointers to virtual methods. In general, the pointer to the VTABLE is hidden from view, but it is often implemented as the first element in an instance of a class.

When a derived class does not have a member function that its parent class does implement as virtual, the parent's method will be called.