This distinction is deliberate due to differences between Objective-C and C ++ object models. In particular, taking into account the pointer to the Objective-C object, you can convert / drop this pointer to the base class or derived class without actually changing the value of the pointer: the address of the object is the same independently.
Since C ++ allows multiple and virtual inheritance, this does not apply to C ++ objects: if I have a pointer to a C ++ class and I pass / convert this pointer to a base class or derived class, I may have to configure pointer values. For example, consider:
class A { int x; } class B { int y; } class C : public A, public B { } B *getC() { C *c = new C; return c; }
Let's say that the new C object in getC () is allocated at 0x10. The value of the 'c' pointer is 0x10. In the return statement, this pointer to C needs to be adjusted to point to the subobject B inside C. Since B comes after the inheritance list of A in C, it will (usually) be laid out after A, so this means adding an offset of 4 bytes (= = sizeof (A)) to the pointer, so the returned pointer will be 0x14. Similarly, casting B * to C * would subtract 4 bytes from the pointer to account for the offset B inside C. When it comes to virtual base classes, the idea is the same, but the offsets are no longer known, compile-time constants: at runtime, they access through vtable.
Now consider the effect this has on assignment, for example:
C (^getC)(); B (^getB)(); getB = getC;
The getC block returns a pointer to C. To turn it into a block that returns a pointer to B, we will need to adjust the pointer returned from each call to the block by adding 4 bytes. This is not a block adjustment; this is an adjustment to the value of the pointer returned by the block. This can be realized by synthesizing a new block, which wraps the previous block and performs tuning, for example,
getB = ^B() { return getC() }
This is implemented in a compiler that already introduces similar "thunks" when overriding a virtual function with a function that requires a covariant return type that needs to be configured. However, an additional problem arises with blocks: blocks allow you to compare equality with ==, so to evaluate "getB == getC" we would need to be able to look at the thunk that would be generated by assigning "getB = getC" to compare the base block pointers. Again, this can be implemented, but it will require much heavier runtime blocks, capable of creating (uniqued) thunks, capable of performing these adjustments to the return value (as well as for any contravariant parameters). Although all this is technically possible, the cost (in size, complexity and lead time) outweighs the benefits.
Returning to Objective-C, an object model with a single inheritance never needs any adjustments to the object pointer: only one address points to this Objective-C object, regardless of the static type of the pointer, so covariance / contravariance never requires any tricks and block assignment is a simple pointer assignment (+ _Block_copy / _Block_release with ARC).