I attempt to modify the vfptr of a Base object to point to vtable which class Derived owns:
#include<iostream>
using namespace std;
class Base {
public:
virtual void func() { cout << "Base::func()" << endl; }
Base() = default;
Base(const Base&);
};
Base::Base(const Base&b) {
*((int*)(this)) = *((int*)(&b)); //modify the vfptr
}
class Derived : public Base {
public:
virtual void func() { cout << "Derived::func()" << endl; }
};
int main() {
Derived d;
cout << "Derived's vtable: " << *(int*)&d << endl << endl;
Base b = d;
cout << "Base's vtable: " << *(int*)&b << endl << endl;
cout << "pass by value:" << endl;
b.func();
cout << endl;
Base *bp = &b;
cout << "pass by pointer" << endl;
bp->func();
}
Output in VS2017:
Derived's vtable: 9739088
Base's vtable: 9739088
pass by value:
Base::func()
pass by pointer
Derived::func()
We can see that vfptr of object b does point to the Derived vtable after modifing but still call the Base version func() by value.
I wonder if the compiler handles such value-call by static binding even if what is called is a virtual function?
Thank you so much.
I wonder if the compiler handles such value-call by static binding
Base b = d;
b.func();
Yes, it does do static binding here indeed. In fact, using dynamic binding would be pointless because the dynamic type of the object is known to be the same as the static type at compile time.
Related
I am trying to see the effects of calling virtual destructors of classes belonging to a long chain of hierarchy: class A to class E.
Strangely, the destructors do not write anything to the console. I first thought perhaps it was happening because main was exiting too. So, I put all the testing code within a function called test() and invoked from within main() so when test would return, I would see destructor footprints. But, nothing! No "cout" signs on the console show up!
#include <iostream>
using namespace std;
//A constructor cannot be virtual but a destructor can.
class A {
public:
A() {
cout << "A constructor" << endl;
}
virtual ~A() {cout << "A destructor" << endl;}
};
class B :public A {
public:
B() {
cout << "B constructor" << endl;
}
virtual ~B() {cout << "B destructor" << endl;}
};
class C :public B {
public:
C() {
cout << "C constructor" << endl;
}
virtual ~C() {cout << "C destructor" << endl;}
};
class D :public C {
public:
D() {
cout << "D constructor" << endl;
}
~D() {cout << "D destructor" << endl;}
};
class E :public D {
public:
E() {
cout << "E constructor" << endl;
}
~E() {cout << "E destructor" << endl;}
};
void test() {
cout << "Test1 begins..." << endl;
A* a1 = new D();
cout << "Test2 begins..." << endl;
A* a2 = new E();
}
int main() {
test();
return 0;
}
Ummm... you actually leak those.
Every objected created by the new keyword must have an equivilant delete:
void test() {
cout << "Test1 begins..." << endl;
A* a1 = new D();
cout << "Test2 begins..." << endl;
A* a2 = new E();
delete a1;
delete a2;
}
Developers (just in your case) always forgot to delete dynamically allocated objects, so smart pointers were introduce:
void test() {
cout << "Test1 begins..." << endl;
std::unique_ptr<A> a1(new D());
cout << "Test2 begins..." << endl;
std::unique_ptr<A> a2(new E());
}
no need to worry about a leak, as unique_ptr automatically delete their pointee when they get out of scope.
You never delete your raw pointers. Prefer smart pointers to raw ones.
You should add
delete a1;
delete a2;
near the end of your test.
Try also to create some instances of E as an automatic variable (usually on the call stack). For example, insert
E ee;
in between those two delete-s.
In the following code, how can I access Base::g() from pBase? (and still get "pBase->g();" to work as it does below)
#include <iostream>
using namespace std;
class Base
{
public:
virtual void f(){ cout << "Base::f()" << endl; }
virtual void g(){ cout << "Base::g()" << endl; }
void h(){ cout << "Base::h()" << endl; }
};
class Derived : public Base
{
public:
void f(){ cout << "Derived::f()" << endl; }
virtual void g(){ cout << "Derived::g()" << endl; }
void h(){ cout << "Derived::h()" << endl; }
};
int main()
{
Base *pBase = new Derived;
pBase->f();
pBase->g();
pBase->h();
Derived *pDerived = new Derived;
pDerived->f();
pDerived->g();
pDerived->h();
return 0;
}
Output is:
Derived::f()
Derived::g()
Base::h()
Derived::f()
Derived::g()
Derived::h()
Also, is Derived::f() exactly the same as Derived::g()? (ie. automatically defined as virtual?)
Use pBase->Base::g(); to force the call of g in Base.
Yes, Derived::f is virtual. I personally find the re-emphasising of virtual to be in poor taste. Since C++11, you can use the override specifier on overridden functions, and then a compiler issues a diagnostic if virtual is dropped from the base class.
Why does the following program crash? I have a base class whose destructor is not virtual but the child class destructor is virtual:
#include <iostream>
class Base {
public:
Base() {
std::cout << "Base::Base CTOR " << std::endl;
}
~Base() {
std::cout << "Base::Base DTOR " << std::endl;
}
};
class Child : public Base {
public:
Child(){
std::cout << "Child::Child CTOR " << std::endl;
}
virtual ~Child() {
std::cout << "Child::Child DTOR " << std::endl;
}
};
int main (int argc, char **argv) {
Base *ptr = new Child;
delete ptr;
}
What you are observing is called "undefined behavior". Make Base's dtor virtual if you want do call delete on Child instance through Base pointer.
From the 2003 standard, 5.3.5/3:
In the first alternative (delete object), if the static type of the
operand is different from its dynamic type, the static type shall be a
base class of the operand’s dynamic type and the static type shall
have a virtual destructor or the behavior is undefined.
You have undefined behavior because the static type of the pointer operand to delete does not match the dynamic type of the object that it points to and you don't meet the requirements for the exception to this rule that allows passing a pointer to a base class to the object being deleted because this exception requires the base class to have a virtual destructor.
Any behaviour is possible including the code working "as expected" or a crash.
Hope this example helps you get the point:
#include <iostream>
class Base {
public:
Base() {
std::cout << "Base::Base CTOR " << std::endl;
}
~Base() {
std::cout << "Base::Base DTOR " << std::endl;
}
private:
protected:
};
class Child : public Base {
public:
Child(){
std::cout << "Child::Child CTOR " << std::endl;
}
~Child(){
std::cout << "Child::Child DTOR " << std::endl;
}
private:
protected:
};
class gChild : public Child {
public:
gChild(){
std::cout << "Child::Child gCTOR " << std::endl;
}
~gChild(){
std::cout << "Child::Child gDTOR " << std::endl;
}
private:
protected:
};
int main ( int argc, char **argv) {
Base *ptr = new gChild;
delete ptr;
}
if virtual ~Base() ,then all destructors' print gets printed.
if virtual ~child() or virtual ~gChild(),only base destructor gets printed.
It's because the destructors executes in opposite direction.and here behaviour is undefined.You must define the base destructor virtual to get the expected result.
Thanks.
Just look at this:
#include <iostream>
class Base
{
public:
void nonvirtualmethod()
{ std::cout << "Base nonvirtualmethod" << std::endl; }
virtual void virtualmethod()
{ std::cout << "Base virtualmethod" << std::endl; }
};
class Derived: public Base
{
public:
void nonvirtualmethod()
{ std::cout << "Derived nonvirtualmethod" << std::endl; }
virtual void virtualmethod()
{ std::cout << "Derived virtualmethod" << std::endl; }
};
int main()
{
Derived d;
Derived* pd = &d;
Base* pb = &d; //< NOTE: both pd and pb point to the same object
pd->nonvirtualmethod();
pb->nonvirtualmethod();
pd->virtualmethod();
pb->virtualmethod();
}
I gives you the following output:
Derived nonvirtualmethod
Base nonvirtualmethod
Derived virtualmethod
Derived virtualmethod //< invoked by a Base*
This is because there is a difference between the static type of the pb pointer (Base*)
and the dynamic type it points to (Derived).
The difference between virtual and plain methods is that non-virtual methods follow the the static type mapping (so a Base pointer invokes Base::methods), while virtual methods follow the chain of the runtime types, hence if a Base* points to a Derived, the Derived method will be called.
Destructors, in this sense, are nothing special: if it is not virtual, a Base pointer will not invoke the Derived one, hence you are left with an half-destroyed object, that is given back to the memory store.
The reason why this is UB (and not simply denied), is because the "memory store" is not managed by the language itself, but from the platform the program is hosted in: the crash most likely depends on the fact that the missing of the Derived part (still alive) will result in the operating system trying free a block of memory with a wrong starting address.
I was doing a little experiment with virtual destructors to review - wondering if anyone has a simple explanation for the following (using vs 2010):
I Define class hierarchy A-B-C-D, D inherits C, C inherits B, B inherits A, A is the Base;
ran 2 experiments:
First experiment -
A has a virtual Destructor.
B has a non-Virtual Destructor
C has a virtual Destructor
D has a non virtual Destructor
//----------------------------
Allocate 4 objects on the heap of type D - Point a pointer of A*, B* and C* at the first 3 - Leave the 4th as a D* for Completeness.
Delete all 4 Pointers.
As I expected, in all 4 instances, the complete destructor chain is executed in reverse order from D down to A, freeing all memory.
Second Experiment -
A has a non-virtual Destructor ** Changed A to non virtual
B has a non-Virtual Destructor
C has a virtual Destructor
D has a non virtual Distructor
Allocate 4 objects on the heap of type D - Point a pointer of A*, B*, and C* at the first 3 - Leave the 4th as a D* for Completeness.
Deleting C* and D* pointers:
the complete destructor chain is executed in reverse order from D down to A, freeing all memory.
Deleting B*:
B and then A Destructor is run (leak)
Deleting A*:
Only A Destructor is run (leak)
Can anyone explain Why this is?
When D type opjects are allocated in experiment 2, its immediate base class (C) has a virtual destructor - doesnt that tell the compiler to track it with a Vptr and know the memory type? REGARDLESS of the reference?
Thanks
Mike
When D type opjects are allocated in experiment 2, its immediate base class (C) has a virtual destructor - doesnt that tell the compiler to track it with a Vptr and know the memory type? REGARDLESS of the reference?
No.
In your second test case, A and B don't have vptrs/vtables. (And even if they did, a non-virtual member function would still be resolved statically, not dynamically.)
Put another way, a base class does not "inherit" information (such as whether functions are virtual) from derived classes.
When you delete an A* without a virtual destructor, at compile-time the compiler does not know that it will point at runtime to an object with a virtual destructor. The deletion might be of an object with a virtual destructor -- or not. Dynamic binding does not occur.
Is your actual question about why one would use virtual vs non-virtual destructors? Cos having a base class with a non-virtual destructor is bad. See the faq
I have composed almost identical question, so I thought to share it.
Note that I also added some usage of virtual function within the different Ctor's in order to illustrate how it is work (shortly, in each Ctor, the V-table is updated only "up to it" , meaning the virtual function implementation that will be invoked is the most derived until "this point" of the inheritance chain).
A note of mine: In the sample code that runs the given classes, I also added a creation of "Derived" object (B and D) on the STACK --> in order to emphasis that all the considerations regarding "virtual-ness" of Dtor's are applicable when we use pointers (of whatever type) to the class instance.
class A;
void callBack(A const& a);
class A
{
public:
A() { std::cout << "A Ctor " << std::endl; f1(); callBack(*this); /* f3();*/ }
~A() { std::cout << "A Dtor " << std::endl; }
void f1() { std::cout << "A : f1 " << std::endl; }
virtual void f2() const { std::cout << "A : f2 " << std::endl; }
virtual void f3() = 0;
};
class B : public A
{
public:
B() { std::cout << "B Ctor " << std::endl; f1(); callBack(*this); f3(); }
~B() { std::cout << "B Dtor " << std::endl; }
void f1 () { std::cout << "B : f1 " << std::endl;}
void f2() const { std::cout << "B : f2 " << std::endl; }
virtual void f3() { std::cout << "B : f3 " << std::endl; }
};
class C : public A
{
public:
C() { std::cout << "C Ctor " << std::endl; f1(); callBack(*this); f3(); }
virtual ~C() { std::cout << "C Dtor " << std::endl; }
void f1() { std::cout << "C : f1" << std::endl;}
void f2() const { std::cout << "C : f2" << std::endl; }
virtual void f3() const { std::cout << "C : f3" << std::endl; }
};
class D : public C
{
public:
D() { std::cout << "D Ctor " << std::endl; f1(); callBack(*this); }
~D() { std::cout << "D Dtor " << std::endl; }
void f1() { std::cout << "D : f1" << std::endl; }
void f2() const { std::cout << "D : f2 " << std::endl; }
virtual void f3() { std::cout << "D : f3 " << std::endl; }
};
void callBack(A const& a) { a.f2(); }
// =================================================================================================================================
int main()
{
std::cout << "Start of main program" << std::endl;
std::cout << "Creating a D object on the heap" << std::endl;
D* pd = new D;
C* pc = new D;
A* pa = new D;
if (true)
{
std::cout << "Entering Dummy scope # 1 and creating B object on the stack" << std::endl;
B b;
std::cout << "Leaving Dummy scope # 1 with B object within it" << std::endl;
}
if (true)
{
std::cout << "Entering Dummy scope # 2 and creating D object on the stack" << std::endl;
D d;
std::cout << "Leaving Dummy scope # 2 with D object within it" << std::endl;
}
std::cout << "Calling delete on pd (D*) which points on a D object" << std::endl;
delete pd;
std::cout << "Calling delete on pc (C*) which points on a D object" << std::endl;
delete pc;
std::cout << "Calling delete on pa (A*) which points on a D object" << std::endl;
delete pa;
std::cout << "End of main program" << std::endl;
return 0;
}
hey there, why is the base destructor called twice at the end of this program?
#include <iostream>
using namespace std;
class B{
public:
B(){
cout << "BC" << endl; x = 0;
}
virtual ~B(){
cout << "BD" << endl;
}
void f(){
cout << "BF" << endl;
}
virtual void g(){
cout << "BG" << endl;
}
private:
int x;
};
class D: public B{
public:
D(){
cout << "dc" << endl; y = 0;
}
virtual ~D(){
cout << "dd" << endl;
}
void f(){
cout << "df" << endl;
}
virtual void g(){
cout << "dg" << endl;
}
private:
int y;
};
int main(){
B b, * bp = &b;
D d, * dp = &d;
bp->f();
bp->g();
bp = dp;
bp->f();
bp->g();
}
Destructors are called in order, as if they were unwinding the effects of the corresponding constructors. So, first the destructors of the derived objects, then the destructors of the base objects. And making the destructors virtual doesn't have any impact on calling / not calling the base class destructor.
Also to mention, your example could be simplified this way (this code also results in calling the base destructor twice and the derived destructor once):
struct A {
~A() {
// ...
}
};
struct B: A {
~B() {
// ...
}
};
int main() {
A a;
B b;
}
Once it is called for b and once for d
Note when destructor of D called it is automatically calls the destructor of B it is different from ordinary virtual functions. where you need explicitly call base class function to use it.