8

最近 iPhone の開発を行っていた私は、オブジェクトの可変性に関して、iPhone SDK で多く使用されている興味深いデザイン パターンに気付きました。

不変のクラスを定義し、そこNSFooから可変の子孫を派生させるのが典型的なアプローチのようNSMutableFooです。一般に、NSFooクラスはデータ メンバー、ゲッター、および読み取り専用操作を定義し、派生したものNSMutableFooはセッターと変更操作に追加されます。

C++ に慣れてきた私は、これが C++ で同じコードを書く場合とはまったく逆のように思われることに気付きました。確かにそのアプローチを取ることもできますが、より簡潔なアプローチは、単一のFooクラスを作成し、getter と読み取り専用操作をconst関数としてマークし、可変操作と setter を同じクラスに実装することだと私には思えます。Foo const*その後、変更可能なクラスになりますが、タイプFoo const&などはすべて実質的に不変の同等物です。

私の質問は、状況に対する私の見解は理にかなっていますか? Objective-C の動作が異なる理由は理解できますが、C++ の 2 クラス アプローチには、私が見逃した利点はありますか? それとも私はポイントを完全に見逃していますか?

あまり深刻な質問ではありません - 何よりも私自身の好奇心のためです.

4

2 に答える 2

4

Objective-C は動的すぎます。C++ では、const 修飾はコンパイル時に強制され、実行時の const 修飾の違反 (const 修飾されていないポインターを介して const 修飾されたオブジェクトを変更するなど) は未定義の動作です。

これは、Objective-C にプライベート メソッドがない理由と一部同じです。任意のオブジェクトに任意のメッセージを自由に送信できます。ランタイム ディスパッチは、オブジェクトとメッセージを受け取り、呼び出すメソッドの実装を解決します。

const修飾されたオブジェクトが修飾されたメソッドのみを呼び出すことができる場合const、Objective-C および Foundation の動的な性質が完全に台無しになります。これは、そのようなチェックを実行時に行う必要があるためです (最初のチェックでは、送信されるメッセージが 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 の動的な性質が維持され、ランタイムがシンプルに保たれます。少し前に、private メソッドについて同様のトピックがありました。

于 2010-06-10T00:53:01.300 に答える
0

考え...

Mac はご存知のように、C++ では、"A" と "const A" を 2 つの異なる型と考えることができます。

  1. 「A」および「A &」は、「const A」および「const A &」などに暗黙的にキャストできます...
  2. 「const A &」は「A &」などに const_cast することができます...

コンパイラは、式などを介して型修飾子の継承と伝播を処理します。

NS の人々が ..Mutable.. 規則を選んだ理由はいくつかあると思います。私の最初の推測では、NextStep が最初に開拓されたとき、C は "const" をサポートしておらず、オブジェクト指向もまだサポートしていなかったと思います。さらに重要なことに、可変オブジェクトと不変オブジェクトの実装で特定の最適化が必要でした。たとえば、NSString のような不変の文字列クラスでは、文字列を「プール」すると便利です。これにより、重複する文字列が原子化され、プロセスが使用するメモリが少なくなる可能性があります。(これにはいくつかの欠点がありますが、常にトレードオフがあります。)

C++ では、最初にコピー オン ライトを理解することで、同じ方向に進むことができます。std::string はこれを行うと言われています。

興味深いトピック、
ウィル・ブラッドリー

于 2010-06-10T00:35:46.453 に答える