This question already has answers here:
In C++ Inheritance, Derived class destructor not called when pointer object to base class is pointed to derived class
(2 answers)
Closed 6 years ago.
I'm writing an operating system in C++. I do not have the std libs at my disposal (so I'm not sure if this works normally with std libs). It appears that if I delete an object, it only calls the destructor of the variable type (and it's parents).
For example:
Aa* aa = new Bb();
delete aa;
will only print "destructing Aa". Whereas
Bb* bb = new Bb();
delete bb;
will print both "destructing Bb" and "destructing Aa".
I tried to work around this issue by calling the sub class destructor in the super class destructor (as seen below).
Is there something I'm missing here, or will I have to resort to casting to the concrete type before the initial delete?
class Aa {
public:
~Aa();
};
class Bb : public Aa {
public:
~Bb() {
log("destructing Bb");
}
};
Aa::~Aa() {
log("destructing Aa");
// TODO checks if we are of type Bb
// ((Bb*) this)->~Bb(); // uncomment to test calling sub class destructor
}
You should make the destructor of Aa virtual:
class Aa {
public:
virtual ~Aa();
};
This is a basic concept of c++. You can read on it here (and in many other places).
Your "Aa" destructor is not virtual, so what you are observing is the expected behaviour.
To get the behaviour you expect, declare the destructor as virtual ~Aa() = default; .
Related
This question already has answers here:
What are the rules for calling the base class constructor?
(10 answers)
Closed 1 year ago.
#include <iostream>
using namespace std;
class A{
public:
A(){
cout << "Hello World";
}
};
class B:public A{
public:
B(){
cout << "World";
}
};
int main(){
B obj1;
return 0;
}
Why does this program print Hello WorldWorld, shouldn't it print World because I have created object of class B, so why is the constructor of A being called?
Conceptually, a base class becomes an unnamed sub object in the derived class, whose members are available in the same scope without extra qualification, and must be initialized.
You cannot avoid that initialization - which means a relevant constructor will be called or if it cannot be constructed then compiler will not allow you to inherit.
What you probably mean is whether the constructor should have overridden the base version, the simple answer is it cannot. If you want that effect - which will not work in constructors in a common sense way - you need to use virtual functions and overriding.
This question already has answers here:
call to pure virtual function from base class constructor
(8 answers)
Calling virtual functions inside constructors
(15 answers)
Closed 1 year ago.
I am trying to call an overriden function from the parent, and found out that it just crashes.
This is quite hard to describe, so here the minimal reproducible code:
#include <iostream>
class A
{
public:
A()
{
init1();
}
void init1()
{
printf("1");
init2();
printf("2");
}
virtual void init2() = 0;
};
class B : public A
{
public:
B()
: A()
{}
void init2() override
{
printf("hello");
}
};
int main()
{
B b;
return 0;
}
On MSVC 2019 it crashes, on http://cpp.sh/ it outputs "1" and then main() returns 0, but we never see "hello" or "2".
Why does it crash? What happens from a low level point of view? Is A trying to call its own init2()?
Is there a way of doing it, so I don't have to, in every derived class, add init2() in its constructor?
You can't call a derived class's overriden methods from within a base class constructor (or destructor). The derived class portion of the object doesn't exist yet.
So, to answer your questions:
yes A::A() is trying to call A::init2(), not B::init2(), and thus crashes from calling a pure virtual method.
There are ways (like via CRTP) for a base class constructor to call a derived class method, but doing so has limitations to it (ie, not being able to access any derived class data members since they still don't exist yet, only base class data members can be accessed). In your example, B::init2() doesn't access anyB data members, so it is possible for A::A() to call B::init2(), but in general you really need to wait for B to begin/finish constructing itself before you can safely call B::init2().
This question already has answers here:
Is the whole object freed with a non-virtual destructor and a Base class pointer?
(6 answers)
Closed 3 years ago.
Consider following code:
class Base1 { public: int a1; };
class Base2 { public: int a2; };
class Foo: public Base1, public Base2 {}
int main() {
Foo *foo = new Foo();
Base2 *b = foo;
delete b; // note pointer foo != pointer b
}
How delete knows, where the memory, which should be freed, begins?
Since all the classes contain only atomic integers, is virtual destructor needed in this particular case?
is virtual destructor needed in this particular case?
Yes. Deleting an object through a pointer to a base with non-virtual destructor has undefined behaviour.
How delete knows, where the object starts in the memory?
In case of non-virtual destructor, you pass the starting address to the operator (or if you don't, then you have UB), so there's no mystery.
In case of virtual destructor, virtual dispatch is used. The compiler will somehow implement it to work correctly. Typically, a "vptr" is used.
This question already has answers here:
When to use virtual destructors?
(20 answers)
Closed 6 years ago.
#include <iostream>
using namesapce std;
class A
{
public:
virtual ~A(){cout<<"delete A"<<endl};
};
class B: public A
{
public:
B(int n):n(n){}
void show(){cout<<n<<endl;}
~B(){cout<<"delete B"<<endl;}
private:
int n;
}
int main()
{
A *pa;
B *pb = new B(1);
pa = pb;
delete pa;
pb->show();
return 0;
}
when destructor of calss A is virtual ~A(){...},the output of program:
delete B
delete A
1
when destructor of class A is ~A(){...}, the output of progarm:
delete A
0
why the value of n is different, when destructor of class A is virtual or non virtual? when call destructor of B to destroy object, why the calss member n is still existent?
Your program exhibits undefined behavior. That's the only answer to your "why" question.
Firstly, if destructor of A is not virtual, then doing delete pa in your code leads to undefined behavior. Trying to delete object of type B through a pointer to parent type A * leads to undefined behavior of the destructor of A is not virtual.
Secondly, pb->show() appears to be an attempt to call a method of an already destroyed object. The behavior is undefined as well, regardless of whether destructors are virtual or not.
A *pa;
B *pb = new B(1);
pa = pb;
This is called upcasting. Whenever upcasting is done base class destructor should be made virtual.
Without virtual base destructior, delete pa will call only base class destructor which is undesirable, because it derived class object will never be destroyed and results in memory leak.
Virtual destructor of base class will call first derived class destructor and then it will destruct itself which is desired behavior and does not cause any leak because of upcasting.
This question already has answers here:
Does delete work with pointers to base class?
(2 answers)
Closed 7 years ago.
Does it cause UB if we define a virtual destructor? For intance:
struct A{ virtual ~A(){ } };
struct B : A { };
A *a = new B;
int main()
{
delete a; //UB?
}
coliru
It is fine precisely because the destructor is virtual — otherwise it would have been UB.
In other words, if you want to delete objects of derived type, through pointers of base type, then the destructor of base class must be virtual, else it would be UB. That ensures that the correct destructor (i.e the destructor of derived) is invoked — that is called runtime polymorphism.
"Does it cause UB if we define a virtual destructor?"
No that's just fine as the destructor was declared virtual. Stepping up the vtable and calling ~B first will be handled by delete.
Its fine, so long as the destructor is virtual.
If the destuctor is not, it will not know to delete the members of the subclass.