Menu
Coddy logo textTech

'Self' ポインタ

CoddyのCジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 7/61。

Python や Java のようなオブジェクト指向言語では、object.method() を呼び出すと、言語が自動的にオブジェクト自体をメソッドに渡します。C では、最初の引数として struct への pointer を渡して、これを手動で行う必要があります。

このポインタは、慣例的に self(Python に由来)または this(C++ に由来)と名付けられます。これにより、関数は struct のデータにアクセスして、読み取ったり変更したりできます。

typedef struct {
    int health;
} Player;

void player_take_damage(Player *self, int amount) {
    self->health -= amount;
}

self pointer が、その function をメソッドのように動作させます。どの player を変更するのかを把握しています。これがなければ、function は特定の struct インスタンスにアクセスする方法がありません。この function を呼び出すときは、struct のアドレスを渡します。

Player hero = {100};
player_take_damage(&hero, 25);
// hero.health は現在 75 です

変更するには、構造体を直接渡すのではなくポインターを使用することが不可欠です。構造体を値渡しすると、関数はコピーを受け取り、変更内容は関数が戻ると失われます。ポインターにより、変更が元の構造体に保持されます。

challenge icon

チャレンジ

簡単

Timerモジュールを作成して、経過した秒数を追跡しましょう。メソッドとして機能する関数を通じて構造体の内部状態を変更するために、"self"ポインターパターンを使用する練習をします。

3つのファイルを作成します。

  • timer.h:単一のint secondsメンバーを持つTimer構造体をDeclareします。また、2つの関数もDeclareします。timer_tick(Timerへのポインターをtakes、指定された秒数を加算する)とtimer_reset(Timerへのポインターをtakes、secondsをzeroに戻す)です。シンボルTIMER_Hでinclude guardsを使用します。
  • timer.c:両方の関数をImplementします。timer_tick関数はTimer *selfint amountをacceptし、amountをtimerのsecondsに加算します。timer_reset関数はTimer *selfをacceptし、そのsecondsをzeroに設定します。
  • main.c:TimerをCreateし、それに対して操作を行い、結果を表示します。

2つの整数入力を受け取ります。timerのinitial secondsと、tickで加算するamountです。

mainファイルでは、次の操作を行います。

  1. initial secondsの値でTimerをinitializeする
  2. 指定されたamountを加算するためにtimer_tickをCallする
  3. current secondsをPrintする
  4. timerをresetするためにtimer_resetをCallする
  5. secondsをもう一度Printする(0になるshould)

結果を次のformatでPrintします。

After tick: {seconds}
After reset: {seconds}

たとえば、initial valueが30で、15 secondsを加算する場合、出力は次のようになります。

After tick: 45
After reset: 0

自分で試してみよう

#include <stdio.h>
#include "timer.h"

int main() {
    int initial_seconds, amount_to_add;
    scanf("%d", &initial_seconds);
    scanf("%d", &amount_to_add);
    
    // TODO: Timerを作成し、initial_secondsで初期化する
    
    // TODO: timer_tickを呼び出してamount_to_add秒を追加する
    
    // TODO: 現在の秒数を次の形式で出力する: "After tick: {seconds}"
    
    // TODO: timer_resetを呼び出してタイマーをリセットする
    
    // TODO: 秒数を再度次の形式で出力する: "After reset: {seconds}"
    
    return 0;
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Cオンラインコンパイラ