1. ホーム
  2. c

[解決済み] C言語のOOPでは、暗黙のうちにselfをパラメータとして渡します。

2022-02-17 17:29:20

質問

C言語でOOPを学ぶための例題に取り組んでいます。現在、このようなコードを作成し動作していますが、メソッドに暗黙的にselfをパラメータとして渡すようにすることに興味があります。

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
//#include "Stopwatch.h"


typedef struct stopwatch_s
{
    unsigned int milliseconds;
    unsigned int seconds;
    unsigned int minutes;
    unsigned int hours;

    bool is_enabled;

    void ( *tick )      ( struct stopwatch_s* );
    void ( *start )     ( struct stopwatch_s* );
    void ( *stop )      ( struct stopwatch_s* );
    void ( *reset )     ( struct stopwatch_s* );
} stopwatch_t;

static void tick (stopwatch_t* _self)
{
    stopwatch_t * self = _self;
    if (self->is_enabled)
    {
        self->milliseconds++;
        if (self->milliseconds >= 1000)
        {
            self->milliseconds = 0;
            self->seconds++;

            if (self->seconds >= 60)
            {
                self->seconds = 0;
                self->minutes++;

                if (self->minutes >= 60)
                {
                    self->minutes = 0;
                    self->hours++;
                }
            }
        }
    }
}

static void start (stopwatch_t* _self)
{
    stopwatch_t * self = _self;
    self->is_enabled = true;
}

static void stop (stopwatch_t* _self)
{
    stopwatch_t * self = _self;
    self->is_enabled = false;
}

static void reset (stopwatch_t* _self)
{
    stopwatch_t * self = _self;
    self->is_enabled = false;
    self->milliseconds = 0;
    self->seconds = 0;
    self->minutes = 0;
    self->hours = 0;
}

void * new_stopwatch()
{
    stopwatch_t * newInstance = (stopwatch_t *)calloc(1, sizeof(stopwatch_t));
    newInstance->is_enabled = false;
    newInstance->milliseconds = 0;
    newInstance->seconds = 0;
    newInstance->minutes = 0;
    newInstance->hours = 0;
    newInstance->tick = &tick;
    newInstance->start = &start;
    newInstance->stop = &stop;
    newInstance->reset = &reset;

    return newInstance;
}

void main()
{
    struct stopwatch_s * Stopwatch = new_stopwatch();
    printf ("Initial: %d\n", Stopwatch->milliseconds);
    Stopwatch->start (Stopwatch);
    Stopwatch->tick (Stopwatch);
    Stopwatch->tick (Stopwatch);
    Stopwatch->tick (Stopwatch);
    printf ("Started: %d\n", Stopwatch->milliseconds);
    Stopwatch->stop (Stopwatch);
    Stopwatch->tick (Stopwatch);
    printf ("Stopped: %d\n", Stopwatch->milliseconds);
    Stopwatch->reset (Stopwatch);
    printf ("Reset: %d\n", Stopwatch->milliseconds);    
}

を読み込んで、次のようにしてみました。 ANSI-Cによるオブジェクト指向プログラミング の代わりに、quot;object" をどのように構成すればよいのか、理解できないのです。

Stopwatch->tick(Stopwatch);

を書くことができます。

Stopwatch->tick();

解決方法は?

<ブロッククオート

オブジェクトをどのように構成すればよいのかがわかりません。

Stopwatch->tick(Stopwatch);

を書くことができます。 Stopwatch->tick();

これは標準的なC言語では不可能で、レシーバを 明示的 を持つC++とは対照的に、C関数の正式な引数です。 this として 暗黙の 形式)。

しかし

  • 一般に、すべてのメソッド関数を1つの struct へのポインタで開始するようにします。 struct ). について読む vtable -s.

  • を与えないようにするためのマクロ(あるいはインライン関数)を用意することができます。 Stopwatch を2回書くことになります。 TICK(Stopwatch) ではなく Stopwatch->tick(); を使用します。 statement-expr の拡張機能です。 GCC が便利かもしれません。

GTKとその ゴブジェクトシステム C のためのかわいいオブジェクトシステムの一例として ObjVLispモデル というウィキページがあります。 仮想メソッドテーブル . たぶん 本案 報告書と RefPerSys と、また 故J.Pitrat氏のブログ .

ところで、ファーストクラスのメソッドセレクタ(おそらく整数値か、何らかの共通のセレクタ型へのポインタ)を持っていると判断し、バリアディックな send ディスパッチ 関数(つまり send(StopWatch,TICK_SEL) の代わりに、夢のような Stopwatch->tick() )またはマクロを使用します。例えば libffi が便利です。昔の Xview はインスピレーションを与えてくれるかもしれません。

最後に、多くの空想的なオブジェクトレイヤーの実装者のように、メタプログラミングを使用して、いくつかのCコード生成ツール(例えば moc Qtの場合)。をカスタマイズすることを検討してもいいかもしれません。 GCC でコンパイルします。 MELT そのような目的のために を作ったり トランスレータ (参照 これ のように)あなたの空想的なOOP方言からCに変更することができます。 VALA または スウィッグ または ビッグルー または チキン・スキーム も参照してください。 これ ). あるいは、外部のプリプロセッサ(あなた自身のもの、あるいは m4 または GPP など...)。