データの抽象化について私が理解したのは、技術的な詳細をユーザーから隠し、必要な詳細のみを表示することです。したがって、データの抽象化は OOP 機能です。私の質問は: C はデータの抽象化もサポートしていますか?
もしそうなら、なぜデータ抽象化はオブジェクト指向プログラミング言語の機能であり、手続き型言語の機能ではないのですか?
私の質問に対する答えが「いいえ」の場合、C の構造体や列挙型はどうでしょうか。また、ユーザーから詳細を隠します。
データの抽象化について私が理解したのは、技術的な詳細をユーザーから隠し、必要な詳細のみを表示することです。したがって、データの抽象化は OOP 機能です。私の質問は: C はデータの抽象化もサポートしていますか?
もしそうなら、なぜデータ抽象化はオブジェクト指向プログラミング言語の機能であり、手続き型言語の機能ではないのですか?
私の質問に対する答えが「いいえ」の場合、C の構造体や列挙型はどうでしょうか。また、ユーザーから詳細を隠します。
C でオブジェクト指向プログラミングを行うことは確かに可能です。たとえば、最初の C++ コンパイラは実際には C++ から C へのトランスパイラであり、Python VM は C で書かれていることなどを思い出してください。いわゆる OOP 言語を他の言語と区別するものは、これらの構造、たとえば構文。
抽象化を提供する一般的な方法の 1 つは、関数ポインターです。以下の Linux カーネル ソースの構造体を見てください (include/linux/virtio.h から)。
/**
* virtio_driver - operations for a virtio I/O driver
* @driver: underlying device driver (populate name and owner).
* @id_table: the ids serviced by this driver.
* @feature_table: an array of feature numbers supported by this driver.
* @feature_table_size: number of entries in the feature table array.
* @probe: the function to call when a device is found. Returns 0 or -errno.
* @remove: the function to call when a device is removed.
* @config_changed: optional function to call when the device configuration
* changes; may be called in interrupt context.
*/
struct virtio_driver {
struct device_driver driver;
const struct virtio_device_id *id_table;
const unsigned int *feature_table;
unsigned int feature_table_size;
int (*probe)(struct virtio_device *dev);
void (*scan)(struct virtio_device *dev);
void (*remove)(struct virtio_device *dev);
void (*config_changed)(struct virtio_device *dev);
#ifdef CONFIG_PM
int (*freeze)(struct virtio_device *dev);
int (*restore)(struct virtio_device *dev);
#endif
};
probe
、などはすべてscan
、remove
I/O ドライバーが自身で設定する関数ポインターです。その後、カーネルは、デバイスについて何も知らなくても、任意の I/O ドライバーに対してこれらの関数を呼び出すことができます。これは、C での抽象化の例です。この特定の例の詳細については、この記事を参照してください。
データ抽象化のもう 1 つの形式は、不透明ポインターです。不透明なデータ型がヘッダー ファイルで宣言されていますが、定義が公開されることはありません。型の定義を知らないコードは、その値にアクセスすることはできず、その値へのポインターのみを使用します。ウィキペディアの不透明なデータ型と不透明なポインターを参照してください。
おそらく遭遇したことのある不透明なデータ型の例はFILE
、stdio.h にあります。FILE *
が指す実際のデータは異なりますが、すべてのオペレーティング システムで同じインターフェイスが使用されます。FILE *
を呼び出してを取得し、fopen
他のさまざまな関数呼び出しで操作できますが、それが指すデータが表示されない場合があります。
CI でのオブジェクト指向プログラミングの詳細については、無料のオンライン ブックObject Oriented Programming in ANSI-C をお勧めします。このドブス博士の記事をご覧ください。関連する質問: C でのオブジェクト指向およびCでオブジェクト指向コードを作成できますか? .
C では非表示は簡単で、単にキャストするだけです。
OOPは実行されるかもしれませんが、一部の機能を取得するのはあまり便利ではないと思います (例: 継承) 多分ポリモーフィズムは達成されていると思いますが、自宅で試したことはありません!
ネイティブ C++ ライブラリへのCインターフェイスは一般的で、次のようなものです。
void *obj_create(void); /* return obscure ptr */
int obj_method(void *obj, int somearg);
void obj_destroy(void *obj);
プライベートヘッダーをパブリック分散から分離することです。
編集
AmigaOSには、何年も前から機能している C の基本的な OOP 実装があり、少なくともAROSプロジェクトからまだ使用されています。実装はBOOPSIと呼ばれ、GUI ガジェット (ウィジェット) の一部の基盤でもありますが、説明するためだけに使用できます。objects、ここで簡単な紹介( Amiga Rom Kernel Reference Manualでは、それを使用してより多くのオブジェクトにシグナルをブロードキャストする方法が示されています。これは、パイオニア Qt のスロット/シグナルの実装です)。
私は過去数日間Nim langを調べていましたが、gcc/clang/tinycc などのバックエンドでコンパイルする C コードを生成し (無効になっている可能性のあるランタイムを追加)、いくつかの OOP をサポートしています。