3

最近、頭の中であれこれ考えています。私たちのほとんどは、構造体を作成するために、オブジェクトを参照する前にキーワードを呼び出すことを避けるためCに、通常、構造体の前に a を付けることをよく知っています。もちろん、C はクラスではなく構造体に限定されています。これを補うために、C は構造体専用のグローバル関数を使用してオブジェクト指向アプローチを作成する傾向があります。typedefstruct

例えば:

typedef struct{
    int foo;
    float bar;
    char* baz;
} SomeStruct;

対。

struct AnotherStruct {
    int foo;
    float bar;
    char* baz;
};

AnotherStructstructその型のオブジェクトが関数内で宣言されている場合、その前にprefix キーワードが必要です。例えば:

int main( ... )
{
   struct AnotherStruct obj1; //correct
   SomeStruct obj2; //correct
   struct SomeStruct obj3; //bad
   AnotherStruct obj4; //bad 
}

オブジェクト指向のアプローチに関しては、次のとおりです。

typedef struct {
    //member variables here
} SomeStruct;

SomeStruct* SomeStruct_New( int a, int b, int c )
{
    SomeStruct* obj = calloc( sizeof( SomeStruct ), 1 ); //not sure if that's correct -- been a while since I've used calloc.
    obj.a = a;
    obj.b = b;
    obj.c = c;
    return obj;
}

void SomeStruct_Free( SomeStruct* free )
{
    free( free );
}

これらの関数は、ラッパーを使用せずに実装するのが非常に簡単です。例として使用しているだけです。typedef私の要点は、キーワードなしで宣言する必要のない構造体を C++ で既に作成できstruct、オブジェクト指向アプローチのためにこれらの構造体に関連するカプセル化されていない関数を使用できることを考えると、オブジェクトへのポインターを返すグローバル関数コンストラクターとともに、静的グローバル関数をプライベートメンバー関数として使用することを含む、C++ でコーディングする C アプローチには利点があります。

これは主に好奇心によるもので、C のアプローチを取るためだけに取りたくなることがありますが、これは単なる優先事項かもしれません。

4

4 に答える 4

3

質問の主旨を理解するのはかなり難しいです。あなたの主な尋問は、次のことであると私には思えます。

  • 「単純な」データ + 関数

よりも良い

  • オブジェクト

場合によっては。

いいえ、同等です。

例外 (!) を除いて、C++ で表現するコードはすべて C で表現できます。C++ の対応するコードを読みやすくするのは、単なる構文糖の問題です。否定論者が時流に乗る前に、C で仮想テーブルをエミュレートできます。

それでも、私はむしろ C++ を使用したいと考えています。コンパイラによってチェックされるカプセル化 ( private)、コンパイラ主導のオーバーロード選択、コンパイラ ボイラープレート (テンプレート)。それは単なる構文糖ですが、そのような甘い糖です。

そうは言っても:

class Foo {
  Foo() {}

  friend Foo build(int a, int b);
  friend int getA(Foo const& foo);
  friend int getB(Foo const& foo);

  int a;
  int b;
};

オブジェクト指向と考えることができます。

編集:ポリモーフィズムの単純でダミーの例

#include <stdio.h>

// Interface
typedef void (*FunctionPrint)(void const*);

typedef struct {
  FunctionPrint print;
} PrinterInterface;

void print(void const* item, PrinterInterface const* pi) {
  (*pi->print)(item);
}

// Foo
typedef struct { int a; } Foo;

void printFoo(void const* arg) {
  Foo const* foo = (Foo const*)arg;
  printf("Foo{%d}\n", foo->a);
}

PrinterInterface const FooPI = { &printFoo };

// Bar
typedef struct { char* a; } Bar;

void printBar(void const* arg) {
  Bar const* bar = (Bar const*)arg;
  printf("Bar{\"%s\"}\n", bar->a);
}

PrinterInterface const BarPI = { &printBar };

// Main
int main() {
  Foo foo = { 1 };
  Bar bar = { "Hello, World!" };

  print(&foo, &FooPI);
  print(&bar, &BarPI);
}

結果:

Foo{1}
Bar{"Hello, World!"}
于 2012-02-01T08:33:17.857 に答える
0

私の知る限り、このような宣言は、いくつかの一般的なヘッダー(主にOS APIから来る:windows.hまたは "xlib.h"と考えてください)をCおよびC ++プログラムの両方で、予測できないCおよびC++バージョンで使用する必要があるという理由だけで存在します。 。

そのようなAPIが今日のように書き直された場合(注:インターフェースだけでなくAPI自体)、おそらくそれらの種類の宣言はありません。API開発者にメモリマッピング(構造体がハードウェアまたは外部バイナリ形式にバインドする場合に重要)と「マジックナンバー定義」について確実にする一種の「ろくでなしコーディング」であり、異なる言語の異なるヘッダーで繰り返されることはありません。

于 2012-02-01T08:19:43.823 に答える
0

いいえ、それが理にかなっている C++ のケースはないと思います。

C アプローチを使用する最も明白なケースは、割り込みとスレッド コールバック関数です。ただし、これらは C++ でプライベートな静的メンバーとして記述できるため、優先されます。

一般に、C または C++ の関数からポインターを返すことが理にかなっているケースはほとんどありません。あなたの例は良いオブジェクト指向ではありません。クラスのユーザーに、必要のないときに動的割り当てを使用するように強制します。C で OO コードを記述する場合、通常は割り当てを呼び出し元に任せます。

リアルタイム組み込みプログラミングで、コンストラクターを呼び出したくないためにクラスを完全に回避したい場合をいくつか思いつくことができますが、そのような場合はおそらく C++ をまったく使用しないでしょう。

于 2012-02-01T08:33:24.127 に答える
0

つい最近、あなたが説明したものを(多かれ少なかれ)実装するHorde3Dを使い始めました。C++ で内部的に実装され、C で単純な API を公開します。

このアプローチは、私のように、外国語インターフェースを使用してエンジンを再利用したい人にとって魅力的です。エンジンを SWI-Prolog に結合する作業を行っていますが、Prolog は OOP の方向性に従っていないため、(たとえば) OGREインターフェイスを使用しても何も得られません。OGRE はより多くの機能を備えていますが、シンプルであることにもメリットがあります...

于 2012-02-01T08:34:24.710 に答える