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.
Related
This question already has answers here:
what is side-cast or cross-cast in Dynamic_cast in C++
(2 answers)
Closed 2 years ago.
std::bad_cast: https://en.cppreference.com/w/cpp/types/bad_cast
An exception of this type is thrown when a dynamic_cast to a reference type fails the run-time check (e.g. because the types are not related by inheritance)
So, if the types are not related by inheritance then it throws an error, so how it the following quote hold true?
https://stackoverflow.com/a/332086/462608
You can use it for more than just casting downwards – you can cast sideways or even up another chain.
What does this quote mean? Please give examples.
Sideways cast would be for example like this:
class Base1 { virtual ~Base1() = default; };
class Base2 { virtual ~Base2() = default; };
class Derived: public Base1, public Base2 {};
int main() {
Base1* p1 = new Derived;
Base2* p2 = dynamic_cast<Base2*>(p1);
}
Types Base1 and Base2 are unrelated to each other, but you can cast between the pointers because Derived inherits from both.
I'm not sure what did the original answerer mean by "cast [...] up another chain", but I guess they meant a situation where you would have a Base1* pointer and would cast to Base2 parent.
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:
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; .
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.
This question already has answers here:
call to pure virtual function from base class constructor
(8 answers)
Closed 5 years ago.
class a //my base class
{
public:
a()
{
foo();
}
virtual void foo() = 0;
};
class b : public a
{
public:
void foo()
{
}
};
int main()
{
b obj; //ERROR: undefined reference to a::foo()
}
Why it gives me error? The pure virtual foo is defined. What do I need to change in my code to make it work? I need pure virtual method from base class be called in its constructor.
Calling virtual functions in a constructor is recognised as a bad thing to do.
During base class construction of a derived class object, the type of
the object is that of the base class. Not only do virtual functions
resolve to the base class, but the parts of the language using runtime
type information (e.g., dynamic_cast (see Item 27) and typeid) treat
the object as a base class type.
So your instantiation of b invokes the a constructor. That calls foo(), but it's the foo() on a that gets called. And that (of course) is undefined.
Quoted from a book "Let Us C++"by Yashwant Kanetkar
It is always the member function of the current class , is called.That
is , the virtual mechanism doesn't work within the constructor
So, the foo() of class a gets called.
Since it is declared pure virtual, it will report an error
foo function is called in class a's constructor, and at that time, object b has not been fully constructed yet, hence it's foo implementation is unavailable.
Quoted from "Effective C++":
Don't call virtual functions during construction or destruction,
because such calls will never go to a more derived class than that of
the currently executing constructor or destructor