Why does this code compile and correctly print "Derived"?
template <class Derived>
class Base
{
public:
Base(Derived& d) : derived(d) {}
void f() { std::cout << "Base\n"; }
virtual ~Base() { derived.f(); }
private:
Derived& derived;
};
class Derived : public Base<Derived>
{
public:
Derived() : Base<Derived>(*this) {}
void f() { std::cout << "Derived\n"; }
};
int main()
{
Derived d;
}
But either making Base::f virtual or both Derived::f and Base::f virtual causes "Base" to be printed. Also, changing Derived::f to virtual gives a Invalid memory reference (SIGSEGV). I would expect those two other cases to print "Derived" since I'm calling it from a Derived instance.
Why does this happen?
This is a dangling reference.
You initialize the field Base::derived to be a reference to the Derived object via the Derived constructor, but then you access it in the Base destructor after the Derived object has been destroyed.
Access any object after it has been destroyed (via either pointer or reference) is undefined behavior, so anything might happen.
Related
Example:
class Base {
public:
virtual void f() = 0;
virtual ~Base() { std::cout << "Base::~Base()\n"; }
};
class Derived : public Base {
public:
void f() { }
~Derived() { std::cout << "Derived::~Derived()\n"; }
};
int main() {
Base* p = new Derived();
delete p;
return 0;
}
Output:
Derived::~Derived()
Base::~Base()
I thought only the derived class destructor will be called since the pointed object to be freed is an instance of the derived class.
I have two questions:
Why was the virtual base destructor called?
Is it legally possible (or should it even be possible) to prevent the base class destructor from being called?
Why was the virtual base destructor called?
Because base class should be properly destructed. Derived class can not possibly do this.
Is it legally possible (or should it even be possible) to prevent the
base class destructor from being called?
No, because it would prevent properly destructing the base class (i.e. call it's members destructors)
#include <iostream>
class X{
public:
virtual void f() {std::cout << "1";}
};
class Y : public X{
public:
void f() {std::cout << "2";}
void g() {std::cout << "3";}
};
class Z : public Y{
public:
virtual void f() {std::cout << "4";}
void g() {std::cout << "5";}
virtual void k() {std::cout << "6";}
};
void main()
{
X *x = new Z;
Y *y = new Z;
Z *z = new Z;
x->f(); // 4
y->f(); // 4
y->g(); // 3
z->f(); // 4
z->g(); // 5
z->k(); // 6
system("PAUSE");
}
Output: 443456.
I got confused, why did it not print '2' when doing 'y->f()'? f() inside Y class isn't a virtual function.
I'd like to know more about it, thank you for the help.
why did it not print '2' when doing 'y->f(x)'? f() inside Y class isn't a virtual function.
Y::f is a virtual function. If a base class has a virtual function by the same name, then the derived class function is implicitly virtual as well.
First of all, overloading isn't relevant here--you don't have any overloaded functions (which would be functions with the same name, but different signatures, at the same scope).
Second, you're not really dealing much with virtual functions either. One one hand, it's true that you've (quite correctly) declared f() as a virtual function in your base class (X).
You've also overridden that virtual function in your derived class Y.
But, the primary time a virtual function means something is when you invoke the virtual function in an object of a derived class via a pointer (or reference) to the base class:
#include <iostream>
class base {
public:
virtual void f() { std::cout << "base::f()\n"; }
void g() { std::cout << "base::g()\n"; }
};
class derived : public base {
public:
virtual void f() { std::cout << "derived::f()\n"; }
virtual void g() { std::cout << "derived::g()\n"; }
};
int main() {
base *b = new base; // first case: pointer to base, base object
base *d = new derived; // second case: pointer to base, derived object
derived *d2 = new derived; // third case: pointer to derived, derived object
b->f(); // invokes base::f
b->g(); // invokes base::g
d->f(); // invokes derived::f
d->g(); // invokes base::g
d2->f(); // invokes derived::f
d2->g(); // invokes derived::g
}
So, in the first case, we have a base pointer, referring to a base object. With this, the derived class might as well not exist--we always get the base class member functions, regardless of whether they're virtual.
The case you asked about is pretty much the same as the third case in this code: we have a pointer to the derived object referring to an object of the derived class. Here again, it doesn't matter whether a function is virtual or not. Since we're using a pointer to a derived, we always get the derived version of each function, regardless of whether it's virtual or not.
The case where virtual functions get interesting is the second one, where we have a pointer to the base class, but it's referring to an object of the derived class. In this case, g() (which isn't virtual) is statically bound, so the function that gets called depends on the type of the pointer. Since we're using a pointer to base, we get base::g() even though the pointer is actually referring to a derived object.
But, with f() (which is virtual), we get "late binding"--even though we're using a pointer to base, when we invoke f(), we invoke derived::f(), because the object being pointed at is a derived object.
So yes, in your code, derived::f() is virtual because it's declared virtual in base--but even if it wasn't virtual, since you used a pointer to the derived class, you'd still have gotten derived::f() even if f() wasn't virtual at all.
The following code is based on the example on page 298 of C++ Templates: the Complete Guide. I removed the parts not relevant to my question.
class Virtual {
public:
virtual void foo() {
}
};
class Base : private Virtual {
public:
void foo() {
std::cout << "Base::foo()" << '\n';
}
};
class Derived : public Base {
public:
void foo() {
std::cout << "Derived::foo()" << '\n';
}
};
int main()
{
Base *p = new Derived;
p->foo(); // calls Derived::foo()
}
I do not understand how the call p->foo() ends up calling Derived::foo. More concretely, the static type of p is Base*. Base::foo is non-virtual. Now, Base privately inherits from 'Virtual', which has its own foo and it looks as if Base::foo somehow gets the virtual specifier from Virtual::foo. What is actually going on here?
The virtualness of foo is inherited from the base class Virtual.
In fact, writing virtual in Derived::foo will be superfluous and many developers will omit it. You cannot undo virtualness once you've marked that function as virtual in a base class.
You can force a call of Base::foo by writing p->Base::foo(); but that's an ugly contrivance.
i do not understand why this behavior occurs:
class Base
{
public:
virtual void enablePolymorphism();
};
class Derived : public Base
{
public:
void enablePolymorphism();
};
class Derived2 : public Base
{
public:
void enablePolymorphism();
};
void callMe(Base base)
{
printf("base");
}
void callMe(Derived derived)
{
printf("derived");
}
void callMe(Derived2 derived2)
{
printf("derived2");
}
int main()
{
Base* pointer = new Derived();
Base* pointer2 = new Derived2();
callMe(*pointer);
callMe(*pointer2);
return 0;
}
this is what i actually want my code to do and i want the method callMe() to be outside the classes therefore i cannot use virtual functions, i want at run-time for the program to call callMe(Derived derived) when i do callMe(*pointer) and callMe(Derived2 derived2) when i do callMe(*pointer2) for which the output would be derivedderived2 but that's not what happens, at compile-time pointer and pointer2 are assumed to be of Base class when dereferenced so the callMe(Base base) is called instead and the output is basebase. How do i achieve the output i want? thank you.
void callMe(A);
void callMe(B);
A*ptr;
callMe(*ptr); // guess which of the above is called?
this has nothing to do with polymorphism, but is simple overloading resolution.
Runtime polymorphism applies only to member functions that are marked with the virtual keyword (or that override a virtual member function):
virtual void callMe();
For a non-member function, or a non-virtual member function, the appropriate overload is selected at compile time based on the declared type (not the runtime type) of the argument(s).
The only thing the compiler sees is that the expression *pointer is of type Base& and therefore succeeds into choosing the correct overload callMe(Base) for the function.
In your case, you can use a polymorphic function instead:
#include <memory>
#include <iostream>
class Base {
public:
virtual void callMe() { std::cout << "called base"; }
};
class Derived : public Base {
public:
virtual void callMe() { std::cout << "called derived"; }
};
int main() {
std::unique_ptr<Base> pointer(new Derived());
pointer->callMe();
return 0;
}
And here is the live example.
During destruction of the derived class object, i first hit the derived class destructor and then the base class destructor (which is as expected). But i was curious to find out - at what point does the functions of the derived class go out of scope (are destroyed).
Does it happen as soon as the control leaves the derived class destructor and goes toward the base? Or does it happen once we done with the base class destructor also.
Thanks
Once the destructor of the most derived class finishes, the dynamic type of the object can be considered that of the next less-derived-type. That is, a call to a virtual method in the base destructor will find that the final overrider at that point in time is at base level. (The opposite occurs during construction)
struct base {
base() { std::cout << type() << std::endl; }
virtual ~base() { std::cout << type() << std::endl; }
virtual std::string type() const {
return "base";
}
};
struct derived : base {
virtual std::string type() const {
return "derived";
}
};
int main() {
base *p = new derived;
std::cout << p->type() << std::endl;
delete p;
}
// output:
// base
// derived
// base
Functions don't get destroyed.
Virtual functions however get their entry in the v-table erased as soon as the derived destructor finishes so you can't call derived virtual functions from the base d'tor.