I have this code:
#include <iostream>
class Super{
public:
virtual void showName();
};
class Special1 : public Super {
public:
void showName();
void sayHello();
};
class Special2 : public Super {
public:
void showName();
void sayGoodbye();
};
void Super::showName() {
std::cout << "I'm super!" << std::endl;
}
void Special1::showName() {
std::cout << "I'm special1" << std::endl;
}
void Special1::sayHello() {
std::cout << "Hello" << std::endl;
}
void Special2::showName() {
std::cout << "I'm special2" << std::endl;
}
void Special2::sayGoodbye() {
std::cout << "Goodbye" << std::endl;
}
int main () {
Super *oSpec=new Super;
Special1 *o1=static_cast<Special1 *>(oSpec);
Special2 *o2=static_cast<Special2 *>(oSpec);
oSpec->showName();
o1->showName();
o2->showName();
o1->sayHello();
o2->sayGoodbye();
delete oSpec;
return 0;
}
When I run it, it shows this output:
I'm super!
I'm super!
I'm super!
Hello
Goodbye
But, if I remove the virtual keyword from the declaration of the Super class:
class Super{
public:
/*virtual*/ void showName();
};
The output becomes the correct one:
I'm super!
I'm special1
I'm special2
Hello
Goodbye
Then, my question is, why the presence of the virtual keyword makes the pointers o1 and o2 run the method Super::showName() instead of Special1::showName() or Special2::showName()?
The output is closer to correct with virtual and incorrect with it (unless you really wanted that). The cast doesn't change the type of the objects, just the type of the pointers. They are still of type Super, and so it's Super::showName that should run.
Casting one pointer type to another pointer type doesn't change the type of the thing pointed to. How could it? The whole point of virtual functions is to be able to call methods on 'generic' pointers and get the correct derived class method.
The classic example of why you use virtual functions is for musicians. You might have a function that causes the entire orchestra to play by calling the Play method on every Musician * it gets passed. For a Pianist, that has to call Pianist::Play.
Normally, the compiler figures out which function to call at compile time -- early binding. The only information the compiler is sure to know is the type of the pointer. The virtual keyword causes the binding to occur late, at run time, when the actual type of the class member is known.
By the way, you can still call the base class method, by using a scope override. For example o1->Super::showName();.
In fact, the result you claim is 'correct' is catastrophic. Running Special1::showName() with the this pointer pointing to an object that is not of type Special1 (or something derived from it) is undefined behavior and can easily lead to a crash.
Because your code in main is wrong. The objects all say "I'm super" because for them (in reality, in the background), the most derived type is still super. That's what they were created as.
Your static cast breaks all the rules, to be undefined behavior (anything can happen), because you tell the compiler that o1 is a Special1, when in fact, it is not a type of Special1.
virtual functions are usually useful when you create a bunch of derived objects, and store them in a pointer/container that holds pointers to the base object. Not the other way around. You want to create pointers of type Special1 and Special2 and store them in pointers to super.
Your cast (Special1 *o1=static_cast<Special1 *>(oSpec);) is undefined behavior in both cases, so any output at all is acceptable as far as the language is concerned. You've taken an object of type Super and lied to the compiler, telling it that it's really a derived class. In this case, what happens is that you still get the result of the parent class Super that it really is.
Your code is just undefined.
Trying to reason why it works in a particular way is useless.
Here:
Super *oSpec=new Super;
oSpec points at an object of type Super.
Thus in these statements. The casts have undefined behavior, as the object pointed at by oSpec is neither a Special 1 or a Special 2).
Special1 *o1=static_cast<Special1 *>(oSpec);
Special2 *o2=static_cast<Special2 *>(oSpec);
If you use dynamica_cast<> (like you should when casting up the class hierarchy). You will find the result are NULL.
Special1 *o1=dynamic_cast<Special1 *>(oSpec);
Special2 *o2=dynamic_cast<Special2 *>(oSpec);
std::cout << "O1(" << (void*)o1 << ") O2(" << (void*)o2 << ")\n";
This will show that both pointers are NULL.
Related
Consider the following classes, which employ the Curiously Recurring Template Pattern (CRTP):
template <typename T>
class Base
{
public:
virtual ~Base() {}
void typeOfThis()
{
cout << "Type of this: " << typeid(this).name() << '\n';
cout << "Type of *this: " << typeid(*this).name() << '\n';
}
void callFuncOfTemplateParam()
{
static_cast<T*>(this)->hello();
}
};
class Derived : public Base<Derived>
{
public:
void hello()
{
cout << "Hello from Derived!" << '\n';
}
};
When I execute the following:
Base<Derived> * basePtrToDerived = new Derived();
basePtrToDerived->typeOfThis();
basePtrToDerived->callFuncOfTemplateParam();
I obtain these results, which make sense to me:
Type of this: P4BaseI7DerivedE
Type of *this: 7Derived
Hello from Derived!
Clearly, the call to hello inside of callFuncOfTemplateParam succeeds because the this pointer points to an instance of Derived, which is why I am able to cast the this pointer from the type Base<Derived>* to the type Derived*.
Now, my confusion arises because when I execute the following:
Base<Derived> * basePtrToBase = new Base<Derived>();
basePtrToBase->typeOfThis();
basePtrToBase->callFuncOfTemplateParam();
I obtain the following results:
Type of this: P4BaseI7DerivedE
Type of *this: 4BaseI7DerivedE
Hello from Derived!
The types of this and *this make sense, but I don't understand how the call to hello succeeds. this doesn't point to an instance of Derived, so why am I able to cast the type of this from Base<Derived> to Derived?
Note that I also replaced the call to static_cast<T*>(this)->hello(); with a call to dynamic_cast<T*>(this)->hello();, and I still obtain the same results. I expected the dynamic_cast to return a nullptr, but it doesn't.
I am very surprised by these results. Thank you for any help clarifying my doubts!
The cast used to call hello() has undefined behavior when T does not match the true type of the object that this points to. But hello() isn't accessing anything via this, so it doesn't really matter what this actually points to. You could just as easily do reinterpret_cast<T*>(12345)->hello() and it would still "work". However you decide to cast this wont make any difference since hello() simply ignores the result (in the case of dynamic_cast, see Does calling a method on a NULL pointer which doesn't access any data ever fail?).
Change your classes to introduce data members that hello() tries to access via this, and you will see very different results (ie, the code will likely crash, or report garbage, etc).
I created the following test code to experiment with the Curiously Recurring Template Pattern, in which I have a Base class with an Interface() and a Derived class with an Implementation. It's modeled directly after the simplest example from the linked Wikipedia page.
#include <iostream>
template <class T>
class Base {
public:
void Interface() {
std::cout << "Base Interface()" << std::endl;
static_cast<T*>(this)->Implementation();
}
};
class Derived : public Base<Derived> {
public:
Derived(int data = 0) : data_(data) {}
void Implementation() {
std::cout << "Derived Implementation(), data_ = " << data_ << std::endl;
}
private:
int data_;
};
int main() {
Base<Derived> b;
b.Interface();
std::cout << std::endl;
Derived d;
d.Interface();
std::cout << std::endl;
return 0;
}
Once compiled, the program runs smoothly and produces the following output:
Base Interface()
Derived Implementation(), data_ = -1450622976
Base Interface()
Derived Implementation(), data_ = 0
The interesting part is the first test, in which a Base pointer is being cast to a Derived pointer, from which the function Implementation() is being called. Inside this function, a "member variable" data_ is being accessed.
To us this is nonsense, but to a compiler it is simply the value at some offset from this object's memory location. However, in this case the Derived class takes more space than the base class, and so if the compiler thinks it's accessing a data member from a Derived object, but actually the object is a Base object, then the memory we are accessing may not belong to this object, or even to this program.
It seems that this programming practice allows us (the programmer) to very easily do very dangerous things, such as making a seemingly reasonable function call that ends up reading from an uncontrolled memory location. Have I interpreted the mechanics of this example correctly? If so, are there techniques within the CRTP paradigm that I've missed to ensure this problem will not show up?
In general static_cast works properly if the pointer you pass there points to an object which contains the target class somewhere in its inheritance hierarchy.
For
Base b;
b.Interface();
a pointer to a real Base object is passed to static_cast, and it is not related to Derived class at all. So after casting you have a pointer that looks like a pointer to Derived, but it still points to a Base object in memory. When you access the data_ member via this pointer, you get a content of some uninitialized area in memory.
I only recently came to the same realization as you did.
After a bit of searching, my answer is yes, you did interpreted the CRTP correctly, and not, you did not miss techniques to avoid the issue.
Which we both find surprising.
Even more surprising for me, was the fact that the code compiles. It is a static downcasting of a base-class pointer, where it is known at compile time that the actual instance is of the base class.
But apparently these casts are allowed, they just lead to undefined behaviors in cases like this one (e.g. see here )
As suggested in the comments by #NathanOliver, a solution to avoid the risk is to make the constructor of the base class protected.
After upcasting a derived class's pointer, a virtual method of the derived class is still called, which seems to me wrong, as slicing should have happened.
Could you please comment what's wrong with this code?
class Base
{
public:
virtual void Hello() { cout << "Hello Base" << endl; }
};
class Derived: public Base
{
public:
void Hello() { cout << "Hello Derived" << endl; }
};
int main()
{
Derived* der = new Derived;
Base* base = dynamic_cast<Base*> (der);
if (base) base->Hello();
}
output: Hello Derived
Slicing did not happen because you didn't work with any values of Base, just pointers to it.
This would cause slicing:
Base base = *der;
But if you want to call a function and suppress dynamic dispatch, you can just do this:
base->Base::Hello();
The function to call is specified statically. This works with der too, of course, avoiding the middle-man.
Your dynamic_cast is not needed here. You can implicitly upcast, because this is trivially verifiable at compile-time. You can use static_cast to downcast, but it's up to you to make sure this is actually correct; dynamic_cast is just a checked version of that.
Pointer casting is about the static type system, which is safety at compile time. E.g. casting is telling the compiler "trust me". It has no bearing at runtime. The nicer cast operations, like dynamic_cast provide some runtime checks (don't do this unless it makes sense), but that still does not affect the polymorphism, it just is a more qualified "trust me"...trust me unless I do something insane.
Polymorphism is about doing the right thing at runtime. When you call a virtual method through a pointer, it will run do the correct operation for the object instance.
In C++, you can ask for a specific resolution using the :: operator, but that is typically reserved for implementation details.
Given the following block of code:
class BaseClass
{
public:
virtual void hello() { cout << "Hello from Base" << endl; }
};
class DerivedClass : public BaseClass
{
public:
void hello() { cout << "Hello from Derived" << endl; }
};
int main()
{
BaseClass base;
DerivedClass derv;
BaseClass* bp = &base;
bp->hello();
bp = &derv;
bp->hello();
}
How is the type that bp is pointing at determined at runtime? I understand it is dynamically bound, but what is the mechanism that does so?
I'm confused because typically the answer is the compiler, however because it is dynamic, it is not the case in this example (or am I mistaken? I assume the compiler this up ahead of time, but what indicates that bp now points to a DerivedClass?). I'm also coming from C#, so this idea is foreign to me seeing as this is native code without the CLR.
When the DerivedClass is constructed, an invisible member is inserted into it's data. That member points to something called a vtable. The vtable has function pointers to the virtual function implementations of the derived class.
Each concrete class (a class which you can instantiate) has it's own vtable somewhere in memory. These tables only get generated if you have virtual functions, part of C++'s motto about not paying for things you don't use.
When the compiler sees bp->hello(), it knows to look for that vtable pointer, and calls the correct function.
Given the following class structure:
class Base
{
virtual void outputMessage() { cout << "Base message!"; }
};
class Derived : public Base
{
virtual void outputMessage() { cout << "Derived message!"; }
}
.. and this code snippet:
Base baseObj;
Derived* convertedObj = (Derived*) &baseObj;
convertedObj->outputMessage();
.. the output will be "Base message!".
Is there any way to cast or manipulate the object to make Derived's version of the outputMessage method to be called polymorphically?
Edit: I will attempt to show the reason why I'm after this:
I am writing migration tools that hook into our main system. For this reason, I need to get access to protected member methods, or customise existing virtual methods. The former I can do by defining a derived class and casting objects to it, to call methods statically. What I can't do is change the behaviour for methods which I do not call statically (ie methods that are called elsewhere in the codebase).
I have also tried creating objects of the derived class directly, but this causes issues in other parts of the system due to the manipulation of the objects passed through the constructor.
No, virtual functions operate on the actual types of the object being pointed to, which in your case is just a simple Base.
Actually, with the down-casting, you're entering undefined-behaviour land here. This can blow off like a bomb with multiple inheritance, where the vtable in the derived class isn't at the same offset as the vtable in the base class.
No Standard-compliant solution
What you're trying to do isn't possible using behaviours guaranteed by the C++ Standard.
If you really MUST do this as a short-term measure to assist your migration, don't depend on it in production, and can adequately verify the behaviour, you could experiment as illustrated below.
Discussion of your attempt
What I'm showing is that you're taking the wrong approach: simply casting a pointer-to-base to a pointer-to-derived doesn't alter the object's vtable pointer.
Deriving a plausible hack
Addressing that, the naive approach is to reconstruct the object in place as a derived object ("placement" new), but this doesn't work either - it will reinitialise the base class members.
What you can possibly do is create a non-derived object that has no data members but the same virtual dispatch table entries (i.e. same virtual functions, same accessibility private/protected/public, same order).
More warnings and caveats
It may work (as it does on my Linux box), but use it at your own risk (I suggest not on production systems).
Further warning: this can only intercept virtual dispatch, and virtual functions can sometimes be dispatched statically when the compiler knows the types at compile time.
~/dev cat hack_vtable.cc
// change vtable of existing object to intercept virtual dispatch...
#include <iostream>
struct B
{
virtual void f() { std::cout << "B::f()\n"; }
std::string s_;
};
struct D : B
{
virtual void f() { std::cout << "D::f()\n"; }
};
struct E
{
virtual void f() { std::cout << "E::f()\n"; }
};
int main()
{
B* p = new B();
p->s_ = "hello";
new (p) D(); // WARNING: reconstructs B members
p->f();
std::cout << '\'' << p->s_ << "'\n"; // no longer "hello"
p->s_ = "world";
new (p) E();
p->f(); // correctly calls E::f()
std::cout << '\'' << p->s_ << "'\n"; // still "world"
}
~/dev try hack_vtable
make: `hack_vtable' is up to date.
D::f()
''
E::f()
'world'
Well, even if you're casting your Base object as a Derived one, internally, it's still a Base object: the vftable of your object (the actual map of functions to RAM pointers) is not updated.
I don't think there is any way to do what you want to do and I don't understand why you'd like to do it.
In this question downcast problem in c++ Robs answer should also be the answer to your problem.
Not at least in legal way. To call Derived class function, you need to have Derived object being referred.