Let's say I have a pointer type that can hold the address of a base class method. Can I assign the address of a subclass method to it and expect it to work correctly? In my case I'm using it with a base class pointer and the dynamic type of the object is the derived class.
struct B
{
typedef void (B::*MethodPtr)();
};
struct D: public B
{
void foo() { cout<<"foo"<<endl; }
};
int main(int argc, char* argv[])
{
D d;
B* pb = &d;
//is the following ok, or undefined behavior?
B::MethodPtr mp = static_cast<B::MethodPtr>(&D::foo);
(pb->*mp)();
}
The standard says this when talking about static_cast:
5.2.9.9 An rvalue of type “pointer to member of D of type cv1 T” can be converted to an rvalue of type “pointer to member of B of type cv2 T”, where B is a base class (clause 10) of D, if a valid standard conversion from “pointer to member of B of type T” to “pointer to member of D of type T” exists (4.11), and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. 63) The null member pointer value (4.11) is converted to the null member pointer value of the destination type. If class B contains the original member, or is a base or derived class of the class containing the original member, the resulting pointer to member points to the original member. Otherwise, the result of the cast is undefined. [Note: although class B need not contain the original member, the dynamic type of the object on which the pointer to member is dereferenced must contain the original member; see 5.5.]
As always, I'm having such a hard time deciphering the standard. It kinda says that it is ok, but I'm not 100% sure if the above text really applies to the situation in my example code.
Downcasting is not allowed without an explicit type cast. The reason for this restriction is that the is-a relationship is not, in most of the cases, symmetric. A derived class could add new data members, and the class member functions that used these data members wouldn't apply to the base class.
Upcasting is safe casting as compare to downcasting. It allows the public inheritance that implicitly cast the reference from one class to another without an explicit typecast.
Is it possible for base class pointers to call methods declared in the derived class only? No, you can only call methods that are part of the class.
[19.4] Is it OK to convert a pointer from a derived class to its base class? Yes.
It's valid.
If class B contains the original member,
B doesn't contain D::Foo, so no.
or is a base [...] of the class containing the original member
B is a base of D, so this holds. As a result:
the resulting pointer to member points to the original member
Clause 5.2.9 9 says you can upcast only if you can also downcast, as specified in § 4.11:
An rvalue of type “pointer to member of B of type cv T,” where B is a class type, can be converted to an rvalue of type “pointer to member of D of type cv T,” where D is a derived class (clause 10) of B. If B is an inaccessible (clause 11), ambiguous (10.2) or virtual (10.1) base class of D, a program that necessitates this conversion is ill-formed.
This just says you can downcast as long as B is accessible, isn't virtual and only appears once in D's inheritance diagram.
The danger inherent in upcasting method pointers is that you could call mp
on an object whose actual type is B. As long as a code block that deals with D::* also deals with D*, you can avoid this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With