1. This is not object slicing:
base *b = new derived;
This is assigning a pointer of type base
to an instance of derived
.
One (very common) example of this in action is in callbacks. Consider this:
class Observer
{
public:
virtual void OnEvent() = 0;
};
class Subject
{
public:
Subject() : observer(0) {}
void SetObserver(Observer* o) { observer = o; }
void FireEvent() { if(observer != 0) observer->OnEvent(); }
private:
Observer* observer;
};
class MyObserver : public Observer
{
public:
void OnEvent() { ::printf("Hi there!\n"); }
};
int main()
{
Subject s;
MyObserver o;
s.SetObserver(&o);
s.FireEvent();
return 0;
}
This should be the expected output:
Hi there!
Notice what is happening here. We're passing in a pointer to an instance of MyObserver
to SetObserver()
even though the function only accepts pointers of type Observer
. This works because MyObserver
(publicly) derives from Observer
. In this case, we say that MyObserver
is-an Observer
.
The Observer
type defines a pure virtual function (The =0
means that the function is pure; it must be implemented by derived classes). The virtual
keyword tells the compiler that calling the function should cause the most-derived function to be executed. The OnEvent()
function in MyObserver
is the most-derived, therefore, that version is called, even though we are calling OnEvent()
on a pointer of type Observer
.
We go through the trouble of doing all this because in this code Subject
doesn't have to know the exact type of its observer - the observers just have to derive from Observer
and the Subject
instance will call the most derived type's implementation of OnEvent()
. This allows for code decoupling - Subject
doesn't depend on MyObserver
, and MyObserver
doesn't depend on Subject
.
2. There's nothing wrong with casting a pointer from a base to derived type per se. The following is in fact legal and guaranteed to work:
class Base {};
class Derived : public Base {};
int main()
{
Derived d;
Base* bp = &d;
Derived* dp = static_cast<Derived*>(bp);
return 0;
}
The line before the return statement in this snippet, however, is undefined:
class Base {};
class Derived1 : public Base {};
class Derived2 : public Base {};
int main()
{
Derived1 d1;
Base* bp = &d1;
Derived2* d2p = static_cast<Derived2*>(bp); // WTF?!
return 0;
}
The value of the d2p
pointer is meaningless, and attempting to access anything in it will certainly cause a crash, because the bp
pointer doesn't actually point to a Derived2
instance, it points to a Derived1
instance. Compilers cannot catch this at compile time, because both Derived1
and Derived2
inherit from Base
, so the cast successfully compiles. This is the main danger with casting from a base to a derived type - you won't know until runtime if the cast actually returns meaningful results.
Of course, unless you use dynamic_cast<>()
, but the cast incurs a runtime penalty. static_cast<>()
involves at most, pointer arithmetic. reinterpret_cast<>()
forces a pointer to take on a different (potentially unrelated) type, without performing any pointer arithmetic. This makes reinterpret_cast<>()
one of the more dangerous casts and should be used only when necessary, especially if static_cast<>()
can do the job.
3. Consider the following:
class Base
{
public:
void Foobar() { ::printf("In Base!\n"); }
};
class Derived : public Base
{
public:
void Foobar() { ::printf("In Derived!\n"); }
};
int main()
{
Derived d;
Derived* dp = &d;
Base* bp = dp;
dp->Foobar();
bp->Foobar();
return 0;
}
If the Foobar()
function is not virtual, then you will get this output:
In Derived!
In Base!
Otherwise, if the Foobar()
function is virtual, then you will get this output:
In Derived!
In Derived!
To guarantee that a call to the virtual function Foobar()
invokes the base implementation via the base pointer, then you have to use the scope resolution operator:
// Prints "In Base!", even if bp actually points
// to an instance of Derived overriding Foobar().
bp->Base::Foobar();