-2

As I know C++ can get the accurate information of object's dynamic type when base class has a virtual function.

class Base
{
public:
    Base() {}
    ~Base() { std::cout << "Base Destructed" << std::endl; }

    virtual void f() {}
};

class Derived : public Base
{
public:
    Derived() {}
    ~Derived() { std::cout << "Derived Destructed" << std::endl; }
};

void PrintTypeName(Base *p)
{
    std::cout << typeid(*p).name() << std::endl;
}

int main()
{
    Base *p = new Derived();
    PrintTypeName(p);
    delete p;
}

The code above can print the correct object type, but why it can't call the correct destructor.

I tested it on g++ and Windows compiler, they gave the same result. I know if I make the Base destructor virtual, it can destruct right way.

But I want to know why do not call the destructor by typeid.

Rhysol
  • 481
  • 1
  • 3
  • 12
  • 5
    You need to declare the destructor as virtual. Why should the C++ runtime perform extra calculation just to allow programmers to ignore the language standard? – paddy Mar 05 '19 at 04:57
  • @paddy I know that. C++ know the run-time type, but can't destruct correct. I want to know the reason. Why language specification or compiler do not implement this feature. – Rhysol Mar 05 '19 at 05:01
  • 7
    Because this feature has a cost, and you don't pay in C++ for what you don't ask. Nothing more to it. – StoryTeller - Unslander Monica Mar 05 '19 at 05:02
  • I'm voting to close this question as off-topic because it isn't on-topic. The help center explains that there are four types of on-topic question; this question doesn't fall into any of the on-topic categories. – davmac Mar 05 '19 at 05:11
  • It is destructing correctly, i.e. it is destructing according to what you have asked. WhatYouGetIsWhatYouAsk – Paul Childs Mar 05 '19 at 05:18

2 Answers2

6

If a method is not marked as virtual, it is not stored in the virtual table. In this case, the destructor is not stored in the virtual table. So it cannot be called.

With the current code, the vtables will look like this:

vtable for Derived:
        .quad   0
        .quad   typeinfo for Derived
        .quad   Base::f()
vtable for Base:
        .quad   0
        .quad   typeinfo for Base
        .quad   Base::f()

See Demo here

If the destructor is marked virtual in Base, the vtables will look like this:

vtable for Derived:
        .quad   0
        .quad   typeinfo for Derived
        .quad   Derived::~Derived() [complete object destructor]
        .quad   Derived::~Derived() [deleting destructor]
        .quad   Base::f()
vtable for Base:
        .quad   0
        .quad   typeinfo for Base
        .quad   Base::~Base() [complete object destructor]
        .quad   Base::~Base() [deleting destructor]
        .quad   Base::f()

See Demo here

P.W
  • 26,289
  • 6
  • 39
  • 76
  • Vtable is not what I want to ask – Rhysol Mar 05 '19 at 05:16
  • Your statement in the question: "But I want too know why do not call the destructor by typeid first and then find destrcutor in **virtual table**." – P.W Mar 05 '19 at 05:18
  • Sorry for that, I fixed it. – Rhysol Mar 05 '19 at 05:26
  • As others have pointed out, in C++, we only pay for what we want to use. When you don't mark a function as virtual, you are indicating that you do not want the costs associated with that. – P.W Mar 05 '19 at 05:39
0

Always remember to make the base class destructor virtual if you are planning to derive classes from it.

marking it virtual in the base class will tell the compiler that it wants to destroy the derived object as well, while deleting the base object.

class Base
{
public:
    Base() {}
    virtual ~Base() { std::cout << "Base Destructed" << std::endl; }

    virtual void f() {}
};

But a point to note will be, you don't put virtual in front of functions, which you don't intend to override. Because this comes with an added cost maintaining a virtual table.

https://www.crashhandler.com/2019/03/make-destructors-destroy-virtually.html This is a blog post by me on this.

Destructor
  • 523
  • 1
  • 3
  • 13