问题
Is it legal to cast a pointer to a method of derived class to a pointer to a method of base class, even though the base class does not declare any methods, especially of the "casted" method is called through an object of type base class, as follows:
// works in VS 2008 and g++ 4.5.3
struct Base
{
};
struct Fuu : public Base
{
void bar(){ std::cout << "Fuu::bar" << std::endl; }
void bax(){ std::cout << "Fuu::bax" << std::endl; }
};
struct Foo : public Base
{
void bar(){ std::cout << "Foo::bar" << std::endl; }
void bax(){ std::cout << "Foo::bax" << std::endl; }
};
typedef void (Base::*PtrToMethod)();
int main()
{
PtrToMethod ptr1 = (PtrToMethod) &Foo::bax;
PtrToMethod ptr2 = (PtrToMethod) &Fuu::bax;
Base *f1 = new Foo;
Base *f2 = new Fuu;
(f1->*ptr1)();
(f2->*ptr2)();
}
回答1:
It's worth noting that the reason the target object is contravariant is because this
is effectively a parameter being passed to the function, and parameters are, in theory, contravariant (if the function can use a Base*
, it can be safely plugged into any algorithm which provides only Derived*
as the actual arguments).
However, for arbitrary parameters, a shim may be needed to adjust the pointer, if the base subobject is not placed at the beginning of the derived class layout. With pointer-to-members, pointer adjustment for the this
pointer is built into the language. (And for this reason, pointer-to-member-of-class-with-virtual-inheritance can get quite large)
回答2:
No. This is described in section 4.11 of the standard (I have n3337.pdf draft):
A prvalue of type “pointer to member of B of type cv T”, where B is a class type, can be converted to a prvalue 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, or a base class of a virtual base class of D, a program that necessitates this conversion is ill-formed. The result of the conversion refers to the same member as the pointer to member before the conversion took place, but it refers to the base class member as if it were a member of the derived class. The result refers to the member in D’s instance of B. Since the result has type “pointer to member of D of type cv T”, it can be dereferenced with a D object. The result is the same as if the pointer to member of B were dereferenced with the B subobject of D. The null member pointer value is converted to the null member pointer value of the destination type.57
In general pointer to member conversions work in the opposite direction then pointers to derived/base classes. Pointers to (sub)objects can be converted towards the base class and pointer to methods can be converted towards more derived classes.
Please note that your program is ill formed if you attempt to call through any of the above pointers when the object involved is not of type Foo/Fuu or their derivative.
While I believe your code takes the risk it looks like similar casting (even without inheritance involved) was heavily used in OWL 2.0 library from Borland at some point.
回答3:
It is legal to cast the pointer. In order to use it, you must cast it back to its original type. The underlying problem is that the pointer-to-function points to a member of the derived class; there is no guarantee that that member is a member of the base class.
来源:https://stackoverflow.com/questions/17746542/casting-a-pointer-to-a-method-of-a-derived-class-to-a-pointer-to-a-method-of-a-b