ブロックの割り当ては、Objective-CクラスのパラメーターとC++クラスのパラメーターに関して異なる動作をすることがわかりました。
この単純なObjective-Cクラス階層があると想像してください。
@interface Fruit : NSObject
@end
@interface Apple : Fruit
@end
次に、次のようなものを書くことができます。
Fruit *(^getFruit)();
Apple *(^getApple)();
getFruit = getApple;
これは、Objective-Cクラスに関して、ブロックはその戻りタイプが共変であることを意味します。より具体的なものを返すブロックは、より一般的なものを返すブロックの「サブクラス」と見なすことができます。ここでgetApple
は、リンゴを届けるブロックを安全にブロックに割り当てることができますgetFruit
。Apple *
確かに、後で使用する場合は、を期待しているときに受け取るために常に保存されますFruit *
。そして、論理的には、その逆は機能getApple = getFruit;
しません。コンパイルされません。なぜなら、私たちが本当にリンゴが欲しいとき、私たちはただの果物を手に入れることに満足していないからです。
同様に、私はこれを書くことができます:
void (^eatFruit)(Fruit *);
void (^eatApple)(Apple *);
eatApple = eatFruit;
これは、ブロックが引数タイプで共変であることを示しています。より一般的な引数を処理できるブロックは、より具体的な引数を処理するブロックが必要な場合に使用できます。ブロックが果物の食べ方を知っていれば、リンゴの食べ方も知っています。繰り返しますが、その逆は真ではなく、これはコンパイルされません:eatFruit = eatApple;
。
これはすべてうまくいっています—Objective-Cでは。次に、これらの類似したC ++クラスがあると仮定して、C++またはObjective-C++でそれを試してみましょう。
class FruitCpp {};
class AppleCpp : public FruitCpp {};
class OrangeCpp : public FruitCpp {};
残念ながら、これらのブロック割り当てはコンパイルされなくなりました。
FruitCpp *(^getFruitCpp)();
AppleCpp *(^getAppleCpp)();
getFruitCpp = getAppleCpp; // error!
void (^eatFruitCpp)(FruitCpp *);
void (^eatAppleCpp)(AppleCpp *);
eatAppleCpp = eatFruitCpp; // error!
Clangは「互換性のないタイプからの割り当て」エラーで文句を言います。したがって、C ++クラスに関しては、ブロックは戻り型とパラメーター型で不変であるように見えます。
何故ですか?私がObjective-Cクラスで行ったのと同じ議論は、C ++クラスにも当てはまりませんか?私は何が欠けていますか?