2016-07-12 2 views
1

C言語で "private"、 "protected"のようなアクセス指定子を実装する方法はありますか?私はインターネット上のソリューションに、特定の他の関数の中でしか関数を利用できないようにするために "静的"と "ifdefs"を使用することについて説明しました。C言語によるデータ隠蔽アクセス指定子の実装

これら以外にも、C++クラスでプライベートおよび保護されたアクセス指定子を使用することに相当するC実装はありますか?

+1

Cはチューリング完全であるので、次のことができるようにする必要があります。問題は、それが努力する価値があり、コードが依然として維持可能であるかどうかです。 C++が必要な場合は、CではなくC++を使用します。これらは異なる言語です。 (地獄、誰もSQLでインラインアセンブラを要求しないのはなぜですか?) – Olaf

+1

@Olaf CでOOPを行うのは完全に合理的です。複雑なCプロジェクトでは、これが最善のアプローチだと思います。欠点は、より多くの定型コードが必要であり、コンパイラがC++コンパイラが検出するエラーの一部を検出できないか、同等のコードに対して全く許可しないことです。また、C++スタイルのRAIIは利用できません。ボーナスは、プログラマがコード内で何が起こるか完全に制御できること、暗黙的なコードexecuton(例外も暗黙のコンストラクタとデストラクタもない)、vtableもプログラマの直接的な制御下にあることです。 – hyde

+0

@hyde:OOPはC++の実装方法だけではありません。情報の隠蔽はOOPの重要な側面ではありません(C++やJavaの部分的なOOPではなく、完全なOOPであるPythonなどの他の言語を参照してください)。私はどこでCでOOPを行うことができない、あるいはそうしてはならないと指摘しますか?明記されていないセマンティクスを読まないでください!しかし、特定の機能を直接サポートする言語を使用するほうが、(その)死を超えて馬を乗るよりも良い点があることは明らかです。 – Olaf

答えて

4

Cには、ユーザー定義の名前空間やアクセス指定子がありません。プリプロセッサの使用を(ab)除外したので、 "クラス"のプライベートな部分にアクセスしようとするとコンパイラのエラーを取得する唯一の方法は、 "プライベート"なものを公開する.hファイルを持たないことです。これらは、モジュールやライブラリの独自の.cファイルに含まれていますが、アプリケーションコードからは除外されていません。また、#ifdefの後ろに隠されています( "private"部品)。

物を隠す一般的な方法の1つは、不透明な構造体AKAの不透明なポインタを使用することです。このアプローチでは、モジュールまたはライブラリの外部のコードは構造体へのポインタしか持ちませんが、構造体定義はありません。そして、モジュールが提供する機能を使用してインスタンスを取得し、アクセスし、最後に解放します。

この方法では、パブリックインターフェイスを簡単に取得できます。パブリックの.hファイルで提供する機能、およびそこに定義されているパブリックサポートの構造体です。プライベートインターフェイスは、完全な構造体の定義が表示されるコードと、public .hファイルにない関数です。

プロテクトされたアクセスは継承を意味します。継承はC言語ではC++とはまったく異なりますが、この答えにはあまりにも広すぎます。これに最も近いのはおそらく、いくつかのレベルの "public"アクセスを提供するいくつかの.hファイルを持つことであろうし、プログラマがそれらに問題を起こさないようにする責任がある。

このアプローチの良い点は、構造体が変更された場合、モジュールを使用する他のコードを変更(または再コンパイル)する必要がないことです。構造体はしばしば共用体であるかもしれませんし、モジュールの関数は実際の型に基づいて分岐し、それを使用しているコードからは見えません。もう一つの良い点は、モジュールが構造体の作成を制御できることです。例えば、structのプールを持ち、ヒープの使用を避けることができます。ヒープはすべてアプリケーションコードには見えません。 1つの欠点は、インライン関数を持つことができないことです。hファイルには構造体の定義が必要ですが、これはここでは隠そうとしています)、パフォーマンスが懸念される場合に最適なコンパイラ最適化ができなくなります。

例(この答えのために書かれた未テストコード):

module.h:参照用

// ...other standard header file stuff ... 

// forward declaration of struct 
struct module_data; 

// "constructor" function 
struct module_data *module_initialize_data(int value); 

// modification function 
int module_update_data(struct module_data *data, int adjust); 

// "destructor" function 
void module_release(struct module_data *data); 

module.c

#include "module.h" 

// struct definition only in the .c file 
struct module_data { 
    int value; 
}; 

struct module_data *module_initialize_data(int value) { 
    struct module_data *data = malloc(sizeof(*data)); 
    data->value = value; 
    return data; 
} 

int module_update_data(struct module_data *data, int adjust) { 
    data->value += adjust; 
    return data->value; 
} 

void module_release(struct module_data *data) { 
    free(data); 
} 

関連するWikipediaのリンク:

+0

Cには名前空間があります!ユーザー定義の名前空間はありません。あなたのアプローチは、OPが求めるものを許可しません。それを実装するのはずっと複雑(ナンセンス)でしょう。 – Olaf

+0

@Olafあなたはスコープを意味しますか、それとも何ですか? – hyde

+0

私は、名前空間とスコープを明確に区別できます。標準を読んでください。 (スコープと名前空間の区別もします)。 – Olaf

5

Cにはアクセス指定子がありません。あなたの呼び出し元から何かを隠す唯一の方法は、ヘッダーにその宣言を提供しないことです。

あなたは翻訳単位で、それは静的にすることができます。

myapi.h

あなたはまた、それを配置することによって、 structの定義を非表示にすることができます
extern int visibleVariable; 
void visibleFunction(); 

myapi.c

int visibleVariable; 
static int invisibleVariable; 
void visibleFunction() { 
    ... 
} 
static void invisibleFunction() { 
    ... 
} 

実装ファイルに格納します。このようにして、構造体のすべてのフィールドは翻訳単位に対してプライベートになります。このアプローチの欠点は、APIのユーザーがstructの型の変数を宣言できないため、ポインタを使用してstructを処理する必要があることです。

Cには継承の概念がないため、protectedに相当するものはありません。

+0

Hmm、実装では 'int i;'も静的です。あなたは '静的'を意味します。しかし、実際にOPが望んでいるようには思えません。 – Olaf

+2

@OlafこれはOPが望むものの一部であるように思えます、彼はもっともっと欲しいです。 – dasblinkenlight

+0

彼は部分的に目に見えないメンバーを持つ単一の 'struct 'を望んでいるようです。面白いことに、C++は実際にそれらを隠すわけではないので、到達するのを難しくしています。 – Olaf