Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to "upcast" a method pointer and use it with base class pointer?

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.

like image 985
Timo Avatar asked Nov 25 '10 01:11

Timo


People also ask

Why downcasting is not safe in C++?

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.

Which is safe Upcasting or downcasting?

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.

Can a base class pointer call methods in the derived class?

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.

Can you convert a pointer from a derived class to its base class?

[19.4] Is it OK to convert a pointer from a derived class to its base class? Yes.


1 Answers

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.

like image 116
outis Avatar answered Sep 30 '22 19:09

outis