Menu
Coddy logo textTech

親メンバーへのアクセス

CoddyのCジャーニー「Object Oriented Programming」セクションの一部 — レッスン 30/61。

構造体の埋め込み(struct embedding)と最初のメンバのルール(first member rule)を理解したところで、実践的な側面に焦点を当てましょう。それは、関数内から埋め込まれた親のデータを読み取り、変更する方法についてです。

関数が Child 構造体(またはそのポインタ)を受け取るとき、親のメンバにアクセスするには、埋め込まれた構造体を経由する必要があります。構文は、値を扱っているかポインタを扱っているかによって異なります。

typedef struct {
    int id;
    int score;
} Parent;

typedef struct {
    Parent parent;
    char grade;
} Child;

Childへのポインタを使用して、アロー演算子で親(parent)に到達し、次にドット演算子でそのメンバにアクセスします。

void update_score(Child* c, int new_score) {
    c->parent.score = new_score;  // アローの後にドット
}

void print_info(Child* c) {
    printf("ID: %d, Score: %d\n", c->parent.id, c->parent.score);
}

(コピー渡し)を使用する場合は、全体を通してドットを使用します:

void show_id(Child c) {
    printf("ID: %d\n", c.parent.id);  // ドット、次にドット
}

この連鎖的なアクセスパターン — child->parent.member または child.parent.member — は、C言語のコンポジションモデルにおいて継承されたデータとやり取りする方法です。真の継承よりも少し冗長ですが、型同士の関係については明示的で明確です。

challenge icon

チャレンジ

簡単

埋め込み構造体内のデータにアクセスし、変更する方法を示す学生の成績管理システムを構築しましょう。Student が埋め込まれた Person を含む階層を作成し、子を介して親のデータを操作する関数を作成します。

コードは3つのファイルに分けて構成します:

  • student.h: インクルードガードを使用して構造体の階層を定義します。name(50文字の文字配列)と age(整数)を持つ Person 構造体を作成します。次に、最初のメンバとして Person を埋め込み、grade フィールド(スコアを表す整数)を追加した Student 構造体を定義します。2つの関数を宣言します:Student* と新しい年齢の値を受け取る set_person_age、および Student* を受け取りすべての情報を表示する print_student です。
  • student.c: 両方の関数を実装します。set_person_age 関数は、埋め込まれた Person 構造体内の年齢を変更する必要があります。ここでは、アロー演算子の後にドット演算子を使用する構文(s->person.age)を練習します。print_student 関数は、埋め込まれた personstudent 自体の両方のすべてのフィールドにアクセスして表示する必要があります。
  • main.c: Student 変数を作成し、そのすべてのフィールドを初期化します。次に、set_person_age を使用して埋め込まれた person の年齢を更新し、print_student を呼び出して結果を表示します。

4つの入力を受け取ります:学生の name(文字列)、initial age(整数)、grade(整数)、および new age(関数を介して更新する整数)。

メインファイルで、初期値を使用して学生を作成し、次に set_person_age を呼び出して年齢を新しい値に変更し、最後に print_student を呼び出して更新された情報を表示します。

出力は以下のようになります:

Name: Emma
Age: 21
Grade: 85

ここで、Emma は名前、21 は(初期の年齢ではなく)更新された年齢、85 は成績です。ここでの主な学習ポイントは、埋め込まれた構造体を介して親のメンバの読み取りと書き込みの両方を行う方法を理解することです。

チートシート

関数から埋め込まれた親構造体のメンバにアクセスするには、ポインタを扱っているか値(実体)を扱っているかに応じて、連鎖的なアクセス構文を使用します。

子構造体へのポインタを使用する場合は、アロー演算子を使用して埋め込まれた親にアクセスし、次にドット記法を使用してそのメンバにアクセスします:

void update_score(Child* c, int new_score) {
    c->parent.score = new_score;  // アローの後にドット
}

void print_info(Child* c) {
    printf("ID: %d, Score: %d\n", c->parent.id, c->parent.score);
}

(コピー渡し)を使用する場合は、全体を通してドット記法を使用します:

void show_id(Child c) {
    printf("ID: %d\n", c.parent.id);  // ドットの後にドット
}

このパターン — child->parent.member または child.parent.member — は、C言語のコンポジションモデルにおいて、継承されたデータへの明示的なアクセスを提供します。

自分で試してみよう

#include <stdio.h>
#include <string.h>
#include "student.h"

int main() {
    char name[50];
    int initial_age, grade, new_age;
    
    // 入力を読み込む
    fgets(name, 50, stdin);
    name[strcspn(name, "\n")] = '\0';  // 改行を削除する
    scanf("%d", &initial_age);
    scanf("%d", &grade);
    scanf("%d", &new_age);
    
    // TODO: Student 変数を作成する
    
    // TODO: 学生のすべてのフィールドを初期化する
    // - strcpy を使用して、埋め込まれた person の name に名前をコピーする
    // - 埋め込まれた person の age を initial_age に設定する
    // - 学生の grade を設定する
    
    // TODO: set_person_age を呼び出して、年齢を new_age に更新する
    
    // TODO: print_student を呼び出して、結果を表示する
    
    return 0;
}
quiz icon腕試し

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

Object Oriented Programmingのすべてのレッスン