Home > Mobile >  What is the effect of calling a virtual method by a base class pointer bound to a derived object tha
What is the effect of calling a virtual method by a base class pointer bound to a derived object tha

Time:03-15

The fllowing questions are:

  1. p->test() should not work after b is destroyed. However, the code is running without any issue, the dynamic binding still works;
  2. when the destructor of A is defined, the dynamic binding doesnot work anymore. What is the logic behind it?
#include <iostream>
using namespace std;
struct A {
    //~A() {} 
    virtual void test() {        cout << 0 << endl;    }
};

class B :public A {
    void test() {        cout << 1 << endl;    }
};

int main() {
    A* p;
    {
        B b;
        p = &b;
    }
    p->test(); // the method called will be different if the destructor of A is removed
}

CodePudding user response:

  1. p->test() should not work after b is destroyed. However, the code is running without any issue, the dynamic binding still works;

It does not "work". p->test() invokes undefined behavior.

  1. when the destructor of A is defined, the dynamic binding doesnot work anymore. What is the logic behind it?

There is no logic behind it, other than implementation details of the compiler you are using, because the C standard does not mandate what a compiler should do with code that has undefined behavior.

For more details on undefined behavior I refer you to https://en.cppreference.com/w/cpp/language/ub

Compilers cannot detect all undefined behavior, but some of it. With gcc you can try -fsanitize=address to see the issue more clearly: https://godbolt.org/z/qxTs4sxcW.

CodePudding user response:

Welcome to the world of Undefined Behaviour! Any access to a deleted object, including calling a method on it invokes undefined behaviour.

That means that the languages requires no specific behaviour, and depending on the internals of the compiler and possibly on any apparently unrelated thing on the computer anything can happen from the expected behaviour (you experienced it) to an immediate crash or unexpected results occuring immediately or later.

Never try to test the result of an UB operation: it can change from one compilation to a new one even with the same configuration or even from one run to the other if it depends on uninitialized memory.

Worse: if the compiler can detect UB in a portion of code, it can optimize out that portion because the language allows it to assume that a program should never invoke UB.

TL/DR: you are invoking UB here. Don't. Just don't.

  • Related