プライベート変数が公的にアクセス可能なヘッダーファイルに記述されているのはなぜですか?


11

わかりました。したがって、これはプログラマにとって主観的な十分な質問ですが、ここに行きます。私は言語とソフトウェアエンジニアリングの実践に関する知識を継続的に広げています...そして、私にはまったく意味をなさない何かに出くわしました。

C ++では、クラス宣言private:のヘッダーファイルにメソッドとパラメーターが含まれます。これは、理論的には、ユーザーに渡してlibにした場合に含めるものです。

Objective-Cでは、@interfacesはほぼ同じことを行い、プライベートメンバーのリストを強制します(少なくとも、実装ファイルにプライベートメソッドを取得する方法があります)。

私が伝えることができることから、JavaとC#では、すべてのパブリックにアクセス可能なプロパティ/メソッドを宣言できるインターフェイス/プロトコルを提供でき、コーダーが実装ファイル内のすべての実装の詳細を隠すことができます。

どうして?カプセル化はOOPの主要な原則の1つですが、なぜC ++とObj-Cにこの基本的な能力が欠けているのですか?Obj-CまたはC ++で、すべての実装を隠すベストプラクティスの回避策がありますか?

おかげで、


4
あなたの痛みが分かります。初めてプライベートフィールドをクラスに追加し、それを使用するすべてのものを再コンパイルする必要があったときに、私はC ++から叫んで逃げました。
ラリーコールマン

@ラリー、私はそれをあまり気にしませんが、それは素晴らしいオブジェクト指向言語として告知されているようですが、「適切に」カプセル化することさえできません。
スティーブン

2
誇大広告を信じないでください。静的と動的の両方のタイプキャンプで、オブジェクト指向を実行するより良い方法があります。
ラリーコールマン

それはではないので、Cに投影さSimulaの67の移植され、そのオブジェクト指向の能力、の、いくつかの点で優れた言語だ
デヴィッド・ソーンリー

Cプログラミングを行う必要があります。次に、Java C#などを含むこれらの言語がなぜそうであるのかをよりよく理解できるようになります。
Henry

回答:


6

問題は、コンパイラがオブジェクトの大きさを知る必要があるかどうかです。もしそうなら、コンパイラーはプライベートメンバーをカウントアップするために知る必要があります。

Javaには、プリミティブ型とオブジェクトがあり、すべてのオブジェクトは個別に割り当てられ、それらを含む変数は実際にはポインターです。したがって、ポインターは固定サイズのオブジェクトであるため、コンパイラーは、ポイント先オブジェクトの実際のサイズを知らなくても、変数がどれだけ大きなものを表すかを知っています。コンストラクターがすべてを処理します。

C ++では、オブジェクトをローカルまたはヒープで表すことができます。したがって、コンパイラは、ローカル変数または配列を割り当てることができるように、オブジェクトの大きさを知る必要があります。

クラスの機能をパブリックインターフェイスとプライベートなものに分割することが望ましい場合があり、それがPIMPL(IMPLementationへのポインター)テクニックの出番です。クラスにはプライベートな実装クラスへのポインターがあり、パブリッククラスメソッドは呼び出すことができますそれ。


コンパイラは、この情報を取得するためにオブジェクトライブラリを参照できませんか?なぜこの情報は人間が読めるのではなく、機械で読めないのですか?
スティーブンフルラニ

@Stephen:コンパイル時には、必ずしもオブジェクトライブラリはありません。オブジェクトのサイズはコンパイルされたコードに影響するため、リンク時だけでなく、コンパイル時に認識される必要があります。さらに、AhでクラスAを定義し、BhでクラスBを定義し、A.cppの関数定義でクラスBのオブジェクトを使用したり、その逆を行うことができます。その場合、オブジェクトコードからオブジェクトサイズを取得する場合は、A.cppとB.cppをそれぞれ先にコンパイルする必要があります。
デビッドソーンリー

コンパイル中にリンクを行うことはできませんか?私はその深さで詳細を知らないことを告白しますが、オブジェクトのインターフェースがそのコンテンツを公開する場合、それらの同じコンテンツはライブラリまたは他の機械可読コンポーネントから公開することはできませんか? 一般にアクセス可能なヘッダーファイルで定義する必要がありますか?これは大部分のC言語の一部であると理解してますが、そうする必要がありますか?
スティーブンフルラニ

1
@Stephen:すべての適切なコンポーネントが存在する場合にのみ、コンパイル中にリンクを実行できます。それでも、それは部分的なコンパイル(オブジェクトサイズ以外のすべて)、部分的なリンク(オブジェクトサイズを取得するため)、そして最終的なコンパイルとリンクを含む複雑なプロセスです。CとC ++が比較的古い言語であることを考えると、そうなることはありませんでした。おそらく誰かがヘッダーファイルなしで新しい言語を設計できるかもしれませんが、それはC ++ではありません。
デビッドソーンリー

14

C ++の設計により、スタック上にオブジェクトを作成するために、コンパイラーはその大きさを知っている必要があります。これを行うには、ヘッダーファイルにすべてのフィールドが存在する必要があります。これは、ヘッダーがインクルードされたときにコンパイラーが確認できるすべてのフィールドです。

たとえば、クラスを定義する場合

class Foo {
    public int a;
    private int b;
};

その後sizeof(Foo)ですsizeof(a) + sizeof(b)。プライベートフィールドを分離するメカニズムがある場合、ヘッダーには

class Foo {
    public int a;
};

sizeof(Foo) = sizeof(a) + ???

プライベートデータを本当に隠したい場合は、pimplイディオムを試してください。

class FooImpl;
class Foo {
    private FooImpl* impl;
}

ヘッダーおよびの実装ファイルFooImplのみでFooの定義。


ああ。私はこれが事実だとは知りませんでした。Java、C#、Obj-Cなどの言語に「クラスオブジェクト」があるので、クラスにオブジェクトの大きさを尋ねることができるのはなぜですか?
スティーブンフルラニ

4
プライベート実装へのポインターであるpimplを使用してみてください。すべてのクラスポインターは同じサイズであるため、実装クラスを定義する必要はなく、宣言するだけです。
スコットウェールズ

それはコメントではなく答えであるべきだと思います。
ラリーコールマン

1

これはすべて設計の選択に帰着します。

C ++またはObjective-Cクラスのプライベート実装の詳細を本当に非表示にする場合は、クラスがサポートする1​​つ以上のインターフェイス(C ++純粋仮想クラス、Objective-C @protocol)を提供するか、クラスを作成します。静的ファクトリメソッドまたはクラスファクトリオブジェクトを提供することにより、自身を構築できます。

プライベート変数がヘッダーファイル/クラス宣言/ @ interfaceで公開される理由は、クラスのコンシューマーがその新しいインスタンスを作成する必要があり、クライアントコードで、new MyClass()または[[MyClass alloc]init]MyClassの大きさを理解するためにコンパイラーが必要なためですオブジェクトは割り当てを行うためのものです。

JavaとC#には、クラスに詳細なプライベート変数もあります。これは例外ではありませんが、インターフェイスパラダイムであるIMOは、これらの言語でより一般的です。いずれの場合もソースコードがない場合がありますが、コンパイル済み/バイトコードに十分なメタデータがあり、この情報を推測できます。C ++およびObjective-Cにはこのメタデータがないため、唯一のオプションはclass / @ interfaceの実際の詳細です。C ++ COMの世界では、クラスのプライベート変数を公開せずに、ヘッダーファイルを提供できます。これは、クラスが純粋仮想であるためです。クラスファクトリオブジェクトも登録されて実際のインスタンスが作成され、さまざまな形式のメタデータがいくつかあります。

C ++およびObjective-Cでは、追加のinterface / @ protocolファイルを作成および管理する場合に比べて、ヘッダーファイルを配布する作業が少なくなります。これは、プライベート実装が頻繁に公開される理由の1つです。

C ++のもう1つの理由はテンプレートです。コンパイラは、提供されたパラメーターに特化したクラスのバージョンを生成するために、クラスの詳細を知る必要があります。クラスのメンバーのサイズはパラメーター化によって異なるため、この情報が必要です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.