Objective C および C++ の可変性設計パターン
-
26-09-2019 - |
質問
最近 iPhone の開発を行ったところ、オブジェクトの変更可能性に関して、iPhone SDK でよく使用されている興味深い設計パターンに気づきました。
典型的なアプローチは不変クラスを定義することのようです NSFoo
, 、そしてそこから可変の子孫を派生させます NSMutableFoo
. 。一般的に、 NSFoo
クラスはデータ メンバー、ゲッター、読み取り専用操作、および派生オブジェクトを定義します。 NSMutableFoo
セッターと変更操作を追加します。
C++ に詳しくなってきた私は、これが C++ で同じコードを書くときのやり方とはまったく逆であるように見えることに気付かずにはいられませんでした。あなたは確かに できた そのアプローチをとると、より簡潔なアプローチは、単一の Foo
クラス、マークゲッターおよび読み取り専用操作 const
関数を実装し、同じクラスに変更可能な操作とセッターも実装します。最終的には可変クラスになりますが、型は Foo const*
, Foo const&
などすべては実質的に不変の同等のものです。
私の質問は、この状況に対する私の見解が理にかなっているかどうかということだと思います。Objective-C の動作が異なる理由は理解できましたが、C++ の 2 クラスのアプローチに見逃している利点はありますか?それとも私は要点を完全に見逃しているのでしょうか?
あまり深刻な質問ではありません。何よりも私自身の好奇心のためです。
解決
はObjective-Cのも動的です。 C ++のconst-資格にコンパイル時に適用され、(例えば、非const修飾ポインタスルーconst修飾オブジェクトを修飾するように)実行時にCONST、資格の違反は、未定義の動作である。
それは、一部のObjective-Cにはプライベートメソッドが存在しない理由と同じです。あなたが任意のオブジェクトに好きなメッセージを送ること自由です。ランタイム・ディスパッチは、オブジェクトとメッセージを受け取り、呼び出すメソッドの実装を解決します。
このようなチェックは実行時に行われる必要があるためconst
修飾オブジェクトのみconst
修飾方法たinvoke、それは完全にObjective-Cのと基礎の動的な性質を台無しになることができれば(最初のチェックは、メッセージがに解決を送信されるかどうかを決定するであろうその特定のインスタンスのconst修飾実装、およびインスタンス自体が)const修飾したかどうかを決定する別のチェック。この理論的な例を考えてみます:
NSArray *mutableArray = [[NSArray alloc] init];
NSString *mutableString = @"I am a mutable string";
const NSString *immutableString = @"I am immutable because I am const-qual'd";
[mutableArray addObject:mutableString];
[mutableArray addObject:immutableString]; // what happens?!
// and what happens here (both immutable and mutable strings would respond
// to the same selectors because they are the same class):
[mutableArray makeObjectsPerformSelector:@selector(aMutableOperation)];
突然、あなたはダイナミクスを失います。それが今であるため、可変および不変オブジェクトは不変または可変コレクションに一緒に座ることができます。
は変更可能なサブクラスを持つことのObjective-Cの動的な性質を保持し、ランタイムをシンプルに保ちます。プライベートメソッドについて、しばらく前に同様の話題がありました。
他のヒント
考え...
Mac の場合、ご存知のとおり、C++ では、「A」と「const A」を 2 つの異なる型として考えることができ、それらの唯一の関係は次のとおりです。
- 「A」と「A &」は、「const A」や「const A &」などに暗黙的にキャストできます。
- 「const A &」は「A &」などに const_cast できます。
コンパイラは、式などによる型修飾子の継承と伝播を処理します。
NS の人々は、..Mutable.. を選択したと思います。この慣例にはいくつかの理由があります。私の最初の推測は、NextStep が最初に開発されたとき、C は "const" をサポートしておらず、まだオブジェクト指向を持っていないと思います。そしてさらに重要なことは、彼らは可変対で特定の最適化を望んでいたということです。不変オブジェクトの実装。たとえば、NSString のような不変文字列クラスでは、文字列を「プール」すると便利です。これにより、重複した文字列を原子化して、プロセスが使用するメモリを削減できる可能性があります。(特定の欠点もありますが、常にトレードオフがあります。)
C++ では、最初に理解することで同じ方向に進むことができます。 コピーオンライト. 。std::string がこれを行うと言われています。
興味深い話題、
ウィル・ブラッドリー