作成日 2007/4/22
最終更新日 2014/5/18
[ Japanese | English ]

クラスとオブジェクト

 クラスとオブジェクトとはどんなものなのかいい加減に説明します。
 ちなみに、クラスとオブジェクトについてはちゃんと理解した方が良いです。
 でないと、継承とかほかの事を理解しても意味がなくなります。
 あ、そういえば、だるまは、ここを理解できずにオブジェクト指向を理解するのを何回挫折したんだろうか…。
 クラスとオブジェクトの関係って、リレーショナルデータベースにおけるテーブルとレコードの関係にすごく似ています。
 それがわかれば、ここではとりあえずはOKかな。

1.クラスとオブジェクト
2.具体例を見る前に
3.具体例1(電話帳の例)
4.具体例2(ある学校の生徒情報と成績の例)
5.具体例1(電話帳の例)のソース
6.具体例2(ある学校の生徒情報と成績の例)のソース


1.クラスとオブジェクト

 オブジェクトについてですが、とりあえず、e-words からの引用で我慢してください。
 ソフトウェアが扱おうとしている現実世界に存在する物理的あるいは抽象的な実体を、属性(データ)と操作(メソッド)の集合としてモデル化し、コンピュータ上に再現したもの。オブジェクトを定義するモデルはクラスと呼ばれる。
 理解できました?
このページのトップへ

2.具体例を見る前に

 これから、クラスとオブジェクトの具体例を説明しますが、以下の注意事項を読んでください。
  1. 以下の例で説明するクラスはエンティティクラスのみです。
     クラスといっても、いろんな種類のクラスがあります。
     以下の具体例に出すクラスはすべてBCEパターンでいうところのエンティティクラスに相当するものです。BCEパターンでは他にもコントロールクラス、バウンダリクラスなどがあります。
     適用するパターンや対象(例えば組み込みの場合)によって、他の種類のクラスがあったりします。
     あ、オブジェクト指向を少し勉強したことのある人であれば、ユーティリティクラスというものを聞いたことがあると思います。Javaであれば、java.lang.Mathクラス のように、単なる計算や関数を集めたクラスで、インスタンスを生成できないクラスです。
     それらはここでは出てきません。
     エンティティクラスは数ある種類のクラスのうち、もっとも基本的なクラスであるため、今回、例にあげることにしました。
     で、エンティティクラスとはどういうものかについてですが、なんだろう。関連したデータをまとめたものかな。
     これは、ER図を描いたことのある人ならわかると思うんだけど。(ER図の"E"はエンティティのEなので。)
  2. 以下の例で、「あ、クラスとオブジェクトって、こんなもんなのか」程度に思って頂ければと考えています。
  3. 以下の例で厳密な定義の理解をしようとは考えないでください。
このページのトップへ

3.具体例1(電話帳の例)

 図1のようなデータがある。クラス図を描け。

電話番号のデータ
図1 電話番号のデータ

■だるまが考えた答え:

電話帳クラス
図2 電話番号のデータから抽出したクラス図

■適当な解説:
 図2の方の、「電話帳」と書いてあるのはクラス名です。
 で、「名前」、「電話番号」は電話帳クラスの属性名になります。
 図2の意味ですが、図1のある行のデータは、名前と電話番号から構成されていますという意味だと思ってください。
 じゃあ、電話帳クラスのオブジェクトにはどういうものがあるのかというと、「名前=山田 太郎、電話番号=01-2345-6789」が電話帳クラスのオブジェクトになっています。(図1の1行1行が電話帳クラスのオブジェクトだと思ってください。)

 あ、この場合のクラスの抽出方法ですが、クラス名は適当に付けました。
クラスの属性の名前は図1の列名からとりました。(属性の型も同じです。)
属性の可視性は省略しました。

 もう一度、注意しておきますが、ここで言っている「クラス」というのは「エンティティクラス」のことであって、そのほかのクラスは、この例のようにはなりませんので。(できれば、「2.具体例を見る前に」をもう一度読んでください。)

このページのトップへ

4.具体例2(ある学校の生徒情報と成績の例)

 図3のようなデータがある。クラス図を描け。

生徒情報のデータと成績情報
図3 生徒情報と成績のデータ

■だるまが考えた答え:
生徒情報と成績のデータから抽出したクラス図
図4 生徒情報と成績のデータから抽出したクラス図

■適当な解説:
 えーと、まず、図4の説明をします。簡単な方から。

 成績情報クラスの「合計得点」、「平均点」の前に「/」(スラッシュ)が付いているけど、これは、この属性は他の属性などから計算して出すことができるものですよという意味です。このような属性のことを「派生属性」と言います。
 通常、クラス図で属性となっているものはエクセルVBAやVB6.0で実装するときはクラスモジュールのモジュールスコープのprivate変数+public プロパティプロシージャとなりますが、派生属性はpublic プロパティプロシージャのみとなります。(functionプロシージャでも良いけど普通はそうはしない。)

 「生徒情報クラス」と「成績情報クラス」を結んでいる直線ですが、これは関連です。で、すぐ近くに書いてある数字は多重度です。
成績情報クラスの近くに書いてある「*」は、生徒情報は成績情報を多数持っていますよという意味です。
逆に、生徒情報クラスの近くに書いてある「1」は、成績情報は誰かの生徒のものであるという意味です。(1つの成績情報が誰のものでもないとか、1つの成績情報が2人のものであるとかはないという意味です。)
 これの実装方法ですが、どうしよう…。ちょっと難しいので、また今度ということで。サンプルを見てください。(2014/5/18追記)
(実は実装するときは、成績情報を管理するクラスを作らないとうまくいきません。そんなクラスなんて無くても実装できないことは無いですが。エクセルでWorkbookクラスを管理するWorkbooksクラスがあるように、管理クラスを作った方が後々楽です。しかし、そのクラスはエンティティクラスではないのでこのページの説明範囲を超えています。まあ、それはまた今度。)
サンプル(VBA版)を見てください。(2014/5/18追記)
 
このページのトップへ

5.具体例1(電話帳の例)のソース

 クラス図だけじゃ、理解できん!というお叱りを受けたので、ソース(実装例)も出します。言語はJavaC++VBAです。

■Javaの場合(動作確認環境:JRE1.6)

電話帳クラス(ファイル名:TelephoneBook.java)
/** 電話帳クラス。1件分のデータを保持します。 */
public class TelephoneBook {
    /** 名前 */
    private String name;
    /** 電話番号 */
    private String number;
    /**
     * 名前を返します。
     * @return 名前
     */
    public String getName() {
        return name;
    }
    /**
     * 名前を設定します。
     * @param name 設定する名前
     */
    public void setName(String name) {
        this.name = name;
    }
    /**
     * 電話番号を返します。
     * @return 電話番号
     */
    public String getNumber() {
        return number;
    }
    /**
     * 電話番号を設定します。
     * @param number 設定する電話番号
     */
    public void setNumber(String number) {
        this.number = number;
    }
}


電話帳オブジェクトを生成して表示してみるサンプル(ファイル名:Main.java)
import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        // オブジェクト作成
        ArrayList<TelephoneBook> teleBook = new ArrayList<TelephoneBook>();

        TelephoneBook obj = null;

        obj = new TelephoneBook();
        obj.setName("山田 太郎");
        obj.setNumber("01-2345-6789");
        teleBook.add(obj);

        obj = new TelephoneBook();
        obj.setName("上野 花子");
        obj.setNumber("03-0303-9999");
        teleBook.add(obj);

        obj = new TelephoneBook();
        obj.setName("だるま 太郎");
        obj.setNumber("04-000-1234");
        teleBook.add(obj);

        // 標準出力
        System.out.println("名前,電話番号");
        System.out.println("=============");
        for(int i=0 ; i < teleBook.size() ; i++ ){
            System.out.println(teleBook.get(i).getName() + "," + teleBook.get(i).getNumber());
        }
    }
}


実行結果(標準出力)
名前,電話番号
=============
山田 太郎,01-2345-6789
上野 花子,03-0303-9999
だるま 太郎,04-000-1234

■C++の場合(動作確認環境:OS:Windows 7 , コンパイラ:VC++ 2010のcl.exe )

電話帳クラスの定義(ファイル名:TelephoneBook.h)
/**
 * @file
 */

#ifndef TELEPHONEBOOK_H_
#define TELEPHONEBOOK_H_

#include <string>

/// @brief 電話帳クラス。1件分のデータを保持します。
class TelephoneBook {
private:
    std::string name;    ///< @brief 名前
    std::string number;  ///< @brief 電話番号
public:
    /// @brief コンストラクタ
    TelephoneBook();
    /// @brief デストラクタ
    virtual ~TelephoneBook();

    /// @brief 名前を返します。 @return 名前
    std::string getName() const;
    /// @brief 名前を設定します。 @param[in] name 設定する名前
    void setName(const std::string& name);
    /// @brief 電話番号を返します。 @return 電話番号
    std::string getNumber() const;
    /// @brief 名前を電話番号します。 @param[in] name 設定する電話番号
    void setNumber(const std::string& number);
};

#endif /* TELEPHONEBOOK_H_ */


電話帳クラスの関数の定義(ファイル名:TelephoneBook.cpp)
#include "TelephoneBook.h"

using namespace std;

TelephoneBook::TelephoneBook() {
}

TelephoneBook::~TelephoneBook() {
}

string TelephoneBook::getName() const {
    return name;
}

void TelephoneBook::setName(const string& name) {
    this->name = name;
}

string TelephoneBook::getNumber() const {
    return number;
}

void TelephoneBook::setNumber(const string& number) {
    this->number = number;
}
※上記の場合、関数定義をヘッダーファイルで行い、インライン関数にした方が効率が良さそうですが、今回はそういうことはしていません。

電話帳オブジェクトを生成して表示してみるサンプル(ファイル名:Main.cpp)
#include <iostream>
#include <string>
#include <vector>
#include "TelephoneBook.h"

using namespace std;

int main() {
    // オブジェクト作成
    vector<TelephoneBook> teleBook;

    TelephoneBook obj;

    obj.setName("山田 太郎");
    obj.setNumber("01-2345-6789");
    teleBook.push_back(obj);

    obj.setName("上野 花子");
    obj.setNumber("03-0303-9999");
    teleBook.push_back(obj);

    obj.setName("だるま 太郎");
    obj.setNumber("04-000-1234");
    teleBook.push_back(obj);

    // 標準出力
    cout << "名前,電話番号\n";
    cout << "=============\n";
    for(int i=0 ; i < teleBook.size() ; i++ ){
        cout << teleBook.at(i).getName()  <<  ","  <<  teleBook.at(i).getNumber() << "\n";
    }
    return 0;
}
※注意:C++のstd::vectorのpush_back関数は、オブジェクトへの参照を配列に追加するのではなく、実体をコピーします。
なので、TelephoneBookオブジェクトの中身を毎回書き換えるなら、TelephoneBookオブジェクトの生成は1回だけで済みます。
分かり難いソースで、申し訳ないのですが、C++はそういうものなのです。


実行結果(標準出力)
名前,電話番号
=============
山田 太郎,01-2345-6789
上野 花子,03-0303-9999
だるま 太郎,04-000-1234

■VBAの場合(動作確認環境:VBA 6.0 )

電話帳クラス(モジュール名:TelephoneBook(クラスモジュール))
''
' 電話帳クラス。1件分のデータを保持します。
Option Explicit

'' 名前
Private m_name As String
'' 電話番号
Private m_number As String

''
' 名前を返します。
' @return 名前
Public Property Get name() As String
    name = m_name
End Property

''
' 名前を設定します。
' @param newName 設定する名前
Public Property Let name(ByVal newName As String)
    m_name = newName
End Property

''
' 電話番号を返します。
' @return 電話番号
Public Property Get number() As String
    number = m_number
End Property

''
' 電話番号を設定します。
' @param newNumber 設定する電話番号
Public Property Let number(ByVal newNumber As String)
    m_number = newNumber
End Property


電話帳オブジェクトを生成して表示してみるサンプル(ファイル名:Main(標準モジュール))
Option Explicit

Sub main()
    ' オブジェクト作成
    Dim teleBook As New Collection
    Dim i As Integer

    Dim obj As TelephoneBook

    Set obj = New TelephoneBook
    obj.name = "山田 太郎"
    obj.number = "01-2345-6789"
    Call teleBook.Add(obj)

    Set obj = New TelephoneBook
    obj.name = "上野 花子"
    obj.number = "03-0303-9999"
    Call teleBook.Add(obj)

    Set obj = New TelephoneBook
    obj.name = "だるま 太郎"
    obj.number = "04-000-1234"
    Call teleBook.Add(obj)

    ' イミディエイトに出力
    Debug.Print "名前,電話番号"
    Debug.Print "============="
    For i = 1 To teleBook.Count() Step 1
        Debug.Print teleBook.Item(i).name & "," & teleBook.Item(i).number
    Next
End Sub


実行結果(イミディエイトウィンドウ)
名前,電話番号
=============
山田 太郎,01-2345-6789
上野 花子,03-0303-9999
だるま 太郎,04-000-1234
このページのトップへ

6.具体例2(ある学校の生徒情報と成績の例)のソース

 こちらも、ソース(実装例)も出します。言語はJavaC++VBAです。

■Javaの場合(動作確認環境:JRE1.6)

成績情報クラス(ファイル名:ResultInformation.java)
import java.util.Calendar;
import java.util.Date;

/** 成績情報。1件分のデータを保持します。 */
public class ResultInformation {
    /** テスト日 */
    private Date testDay;
    /** 国語の得点 */
    private int scoreOfJapanese;
    /** 英語の得点 */
    private int scoreOfEnglish;
    /**
     * テスト日を返します。
     * @return テスト日
     */
    public Date getTestDay() {
        return testDay;
    }
    /**
     * テスト日を設定します。
     * @param testDay 設定するテスト日
     */
    public void setTestDay(Date testDay) {
        this.testDay = testDay;
    }
    /**
     * テスト日を設定します。
     * @param year 年
     * @param month 月(1-12)
     * @param day 日(1-31)
     */
    public void setTestDay(int year, int month, int day) {
        Calendar obj = Calendar.getInstance();
        obj.clear();
        obj.set(year, month - 1, day);
        setTestDay(obj.getTime());
    }
    /**
     * 国語の得点を返します。
     * @return 国語の得点
     */
    public int getScoreOfJapanese() {
        return scoreOfJapanese;
    }
    /**
     * 国語の得点を設定します。
     * @param scoreOfJapanese 設定する国語の得点
     */
    public void setScoreOfJapanese(int scoreOfJapanese) {
        this.scoreOfJapanese = scoreOfJapanese;
    }
    /**
     * 英語の得点を返します。
     * @return 英語の得点
     */
    public int getScoreOfEnglish() {
        return scoreOfEnglish;
    }
    /**
     * 英語の得点を設定します。
     * @param scoreOfEnglish 設定する英語の得点
     */
    public void setScoreOfEnglish(int scoreOfEnglish) {
        this.scoreOfEnglish = scoreOfEnglish;
    }
    /**
     * 合計得点を返します。
     * @return 合計得点
     */
    public int getTotal() {
        return scoreOfJapanese + scoreOfEnglish;
    }
    /**
     * 平均点を返します。
     * @return 平均点
     */
    public double getAverage() {
        return getTotal() / 2.0;
    }
}


生徒情報クラス(ファイル名:StudentInformation.java)
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;

/** 生徒情報。1件分のデータを保持します。 */
public class StudentInformation {
    /** 出席番号 */
    private int attendanceNumber;
    /** 名前 */
    private String name;
    /** 生年月日 */
    private Date dateOfBirth;
    /** 成績情報のリスト */
    private ArrayList<ResultInformation> resultInfoList = new ArrayList<ResultInformation>();
    /**
     * 出席番号を返します。
     * @return 出席番号
     */
    public int getAttendanceNumber() {
        return attendanceNumber;
    }
    /**
     * 出席番号を設定します。
     * @param attendanceNumber 設定する出席番号
     */
    public void setAttendanceNumber(int attendanceNumber) {
        this.attendanceNumber = attendanceNumber;
    }
    /**
     * 名前を返します。
     * @return 名前
     */
    public String getName() {
        return name;
    }
    /**
     * 名前を設定します。
     * @param name 設定する名前
     */
    public void setName(String name) {
        this.name = name;
    }
    /**
     * 生年月日を返します。
     * @return 生年月日
     */
    public Date getDateOfBirth() {
        return dateOfBirth;
    }
    /**
     * 生年月日を設定します。
     * @param dateOfBirth 設定する生年月日
     */
    public void setDateOfBirth(Date dateOfBirth) {
        this.dateOfBirth = dateOfBirth;
    }
    /**
     * 生年月日を設定します。
     * @param year 年
     * @param month 月(1-12)
     * @param day 日(1-31)
     */
    public void setDateOfBirth(int year, int month, int day) {
        Calendar obj = Calendar.getInstance();
        obj.clear();
        obj.set(year, month - 1, day);
        setDateOfBirth(obj.getTime());
    }
    /**
     * 成績情報のリストを返します。
     * @return resultInfoList 成績情報のリスト
     */
    public ArrayList<ResultInformation> getResultInfoList() {
        return resultInfoList;
    }
}


生徒情報と成績情報オブジェクトを生成して表示するサンプル(ファイル名:Main.java)
import java.text.SimpleDateFormat;
import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        // オブジェクト作成
        ArrayList<StudentInformation> stdntInfoList = new ArrayList<StudentInformation>();

        StudentInformation obj = null;
        ResultInformation objR = null;

        obj = new StudentInformation();
        obj.setAttendanceNumber(1);
        obj.setName("山田 太郎");
        obj.setDateOfBirth(1993, 4, 8);
        stdntInfoList.add(obj);
        {
            objR = new ResultInformation();
            objR.setTestDay(2006, 4, 20);
            objR.setScoreOfJapanese(75);
            objR.setScoreOfEnglish(55);
            obj.getResultInfoList().add(objR);

            objR = new ResultInformation();
            objR.setTestDay(2006, 9, 15);
            objR.setScoreOfJapanese(89);
            objR.setScoreOfEnglish(45);
            obj.getResultInfoList().add(objR);

            objR = new ResultInformation();
            objR.setTestDay(2007, 1, 20);
            objR.setScoreOfJapanese(76);
            objR.setScoreOfEnglish(60);
            obj.getResultInfoList().add(objR);
        }

        obj = new StudentInformation();
        obj.setAttendanceNumber(2);
        obj.setName("上野 花子");
        obj.setDateOfBirth(1993, 7, 18);
        stdntInfoList.add(obj);
        {
            objR = new ResultInformation();
            objR.setTestDay(2006, 4, 20);
            objR.setScoreOfJapanese(100);
            objR.setScoreOfEnglish(95);
            obj.getResultInfoList().add(objR);

            objR = new ResultInformation();
            objR.setTestDay(2006, 9, 15);
            objR.setScoreOfJapanese(97);
            objR.setScoreOfEnglish(100);
            obj.getResultInfoList().add(objR);

            objR = new ResultInformation();
            objR.setTestDay(2007, 1, 20);
            objR.setScoreOfJapanese(95);
            objR.setScoreOfEnglish(98);
            obj.getResultInfoList().add(objR);
        }

        obj = new StudentInformation();
        obj.setAttendanceNumber(3);
        obj.setName("だるま 太郎");
        obj.setDateOfBirth(1993, 12, 1);
        stdntInfoList.add(obj);
        {
            objR = new ResultInformation();
            objR.setTestDay(2006, 4, 20);
            objR.setScoreOfJapanese(40);
            objR.setScoreOfEnglish(30);
            obj.getResultInfoList().add(objR);

            objR = new ResultInformation();
            objR.setTestDay(2006, 9, 15);
            objR.setScoreOfJapanese(45);
            objR.setScoreOfEnglish(35);
            obj.getResultInfoList().add(objR);

            objR = new ResultInformation();
            objR.setTestDay(2007, 1, 20);
            objR.setScoreOfJapanese(39);
            objR.setScoreOfEnglish(33);
            obj.getResultInfoList().add(objR);
        }

        obj = new StudentInformation();
        obj.setAttendanceNumber(4);
        obj.setName("土野 三郎");
        obj.setDateOfBirth(1994, 3, 4);
        stdntInfoList.add(obj);
        {
            objR = new ResultInformation();
            objR.setTestDay(2006, 4, 20);
            objR.setScoreOfJapanese(68);
            objR.setScoreOfEnglish(89);
            obj.getResultInfoList().add(objR);

            objR = new ResultInformation();
            objR.setTestDay(2006, 9, 15);
            objR.setScoreOfJapanese(60);
            objR.setScoreOfEnglish(90);
            obj.getResultInfoList().add(objR);

            objR = new ResultInformation();
            objR.setTestDay(2007, 1, 20);
            objR.setScoreOfJapanese(71);
            objR.setScoreOfEnglish(76);
            obj.getResultInfoList().add(objR);
        }

        // 標準出力
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/M/d");
        System.out.println("出席番号,名前,生年月日");
        System.out.println("    テスト日,国語の得点,英語の得点,合計得点,平均点");
        System.out.println("==================================================");
        for (int i = 0; i < stdntInfoList.size(); i++) {
            obj = stdntInfoList.get(i);
            System.out.println(obj.getAttendanceNumber()
                    + "," + obj.getName()
                    + "," + sdf.format(obj.getDateOfBirth()));
            for (int j = 0; j < obj.getResultInfoList().size(); j++) {
                objR = obj.getResultInfoList().get(j);
                System.out.println("    " + sdf.format(objR.getTestDay())
                        + "," + objR.getScoreOfJapanese()
                        + "," + objR.getScoreOfEnglish()
                        + "," + objR.getTotal()
                        + "," + objR.getAverage());
            }
        }
    }
}


実行結果(標準出力)
出席番号,名前,生年月日
    テスト日,国語の得点,英語の得点,合計得点,平均点
==================================================
1,山田 太郎,1993/4/8
    2006/4/20,75,55,130,65.0
    2006/9/15,89,45,134,67.0
    2007/1/20,76,60,136,68.0
2,上野 花子,1993/7/18
    2006/4/20,100,95,195,97.5
    2006/9/15,97,100,197,98.5
    2007/1/20,95,98,193,96.5
3,だるま 太郎,1993/12/1
    2006/4/20,40,30,70,35.0
    2006/9/15,45,35,80,40.0
    2007/1/20,39,33,72,36.0
4,土野 三郎,1994/3/4
    2006/4/20,68,89,157,78.5
    2006/9/15,60,90,150,75.0
    2007/1/20,71,76,147,73.5

■C++の場合(動作確認環境:OS:Windows 7 , コンパイラ:VC++ 2010のcl.exe )

成績情報クラスの定義(ファイル名:ResultInformation.h)
/**
 * @file
 */

#ifndef RESULTINFORMATION_H_
#define RESULTINFORMATION_H_

#include <time.h>

/** 成績情報。1件分のデータを保持します。 */
class ResultInformation {
private:
    struct tm testDay;        ///< @brief テスト日
    int scoreOfJapanese;    ///< @brief 国語の得点
    int scoreOfEnglish;        ///< @brief 英語の得点
public:
    /// @brief コンストラクタ
    ResultInformation();
    /// @brief デストラクタ
    virtual ~ResultInformation();
    /// @brief テスト日を返します。  @return テスト日
    const struct tm& getTestDay() const;
    /// @brief テスト日を設定します。  @param[in] testDay 設定するテスト日
    void setTestDay(const struct tm& testDay);
    /// @brief テスト日を設定します。  @param[in] year 年 @param[in] month 月 @param[in] day 日
    void setTestDay(int year , int month , int day);
    /// @brief 国語の得点を返します。  @return 国語の得点
    int getScoreOfJapanese() const;
    /// @brief 国語の得点を設定します。  @param[in] scoreOfJapanese 設定する国語の得点
    void setScoreOfJapanese(int scoreOfJapanese);
    /// @brief 英語の得点を返します。  @return 英語の得点
    int getScoreOfEnglish() const;
    /// @brief 英語の得点を設定します。  @param[in] scoreOfEnglish 設定する英語の得点
    void setScoreOfEnglish(int scoreOfEnglish);

    /// @brief 合計得点を返します。  @return 合計得点
    int getTotal() const;
    /// @brief 平均点を返します。 @return 平均点
    double getAverage() const;
};

#endif /* RESULTINFORMATION_H_ */


成績情報クラスの関数の定義(ファイル名:ResultInformation.cpp)
#include "ResultInformation.h"

ResultInformation::ResultInformation() {
}

ResultInformation::~ResultInformation() {
}

const struct tm& ResultInformation::getTestDay() const {
    return testDay;
}

void ResultInformation::setTestDay(const struct tm& testDay) {
    this->testDay = testDay;
}

void ResultInformation::setTestDay(int year , int month , int day) {
    struct tm date= {0};
    date.tm_year = year - 1900;
    date.tm_mon = month - 1;
    date.tm_mday = day;
    setTestDay(date);
}

int ResultInformation::getScoreOfJapanese() const {
    return scoreOfJapanese;
}

void ResultInformation::setScoreOfJapanese(int scoreOfJapanese) {
    this->scoreOfJapanese = scoreOfJapanese;
}

int ResultInformation::getScoreOfEnglish() const {
    return scoreOfEnglish;
}

void ResultInformation::setScoreOfEnglish(int scoreOfEnglish) {
    this->scoreOfEnglish = scoreOfEnglish;
}

int ResultInformation::getTotal() const {
    return scoreOfJapanese + scoreOfEnglish;
}

double ResultInformation::getAverage() const {
    return getTotal() / 2.0;
}
※上記の場合、関数定義をヘッダーファイルで行い、インライン関数にした方が効率が良さそうですが、今回はそういうことはしていません。

生徒情報クラスの定義(ファイル名:StudentInformation.h)
/**
 * @file
 */

#ifndef STUDENTINFORMATION_H_
#define STUDENTINFORMATION_H_

#include <time.h>
#include <string>
#include <vector>
#include "ResultInformation.h"

/** 生徒情報。1件分のデータを保持します。 */
class StudentInformation {
private:
    int attendanceNumber;                            ///< @brief 出席番号
    std::string name;                                ///< @brief 名前
    struct tm dateOfBirth;                            ///< @brief 生年月日
    std::vector<ResultInformation> resultInfoList;    ///< @brief 成績情報のリスト
public:
    /// @brief コンストラクタ
    StudentInformation();
    /// @brief デストラクタ
    virtual ~StudentInformation();
    /// @brief 出席番号を返します。  @return 出席番号
    int getAttendanceNumber() const;
    /// @brief 出席番号を設定します。 @param[in] attendanceNumber 出席番号
    void setAttendanceNumber(int attendanceNumber);
    /// @brief 名前を返します。  @return 名前
    const std::string& getName() const;
    /// @brief 名前を設定します。 @param[in] name 名前
    void setName(const std::string& name);
    /// @brief 生年月日を返します。  @return 生年月日
    const struct tm& getDateOfBirth() const;
    /// @brief 生年月日を設定します。 @param[in] dateOfBirth 生年月日
    void setDateOfBirth(const struct tm& dateOfBirth);
    /// @brief 生年月日を設定します。 @param[in] year 年  @param[in] month 月  @param[in] day 日
    void setDateOfBirth(int year , int month , int day);
    /// @brief 成績情報のリストを返します。  @return 成績情報のリスト
    std::vector<ResultInformation>& getResultInfoList();
    /// @brief 成績情報のリストを返します。  @return 成績情報のリスト
    const std::vector<ResultInformation>& getResultInfoList() const;
};

#endif /* STUDENTINFORMATION_H_ */


生徒情報クラスの関数の定義(ファイル名:StudentInformation.cpp)
#include "StudentInformation.h"

using namespace std;

StudentInformation::StudentInformation() {
}

StudentInformation::~StudentInformation() {
}

int StudentInformation::getAttendanceNumber() const {
    return attendanceNumber;
}

void StudentInformation::setAttendanceNumber(int attendanceNumber) {
    this->attendanceNumber = attendanceNumber;
}

const string& StudentInformation::getName() const {
    return name;
}

void StudentInformation::setName(const string& name) {
    this->name = name;
}

const struct tm& StudentInformation::getDateOfBirth() const {
    return dateOfBirth;
}

void StudentInformation::setDateOfBirth(const struct tm& dateOfBirth) {
    this->dateOfBirth = dateOfBirth;
}

void StudentInformation::setDateOfBirth(int year , int month , int day) {
    struct tm date = {0};
    date.tm_year = year - 1900;
    date.tm_mon = month - 1;
    date.tm_mday = day;
    setDateOfBirth(date);
}

vector<ResultInformation>& StudentInformation::getResultInfoList() {
    return resultInfoList;
}

const vector<ResultInformation>& StudentInformation::getResultInfoList() const {
    return resultInfoList;
}
※上記の場合、関数定義をヘッダーファイルで行い、インライン関数にした方が効率が良さそうですが、今回はそういうことはしていません。

生徒情報と成績情報オブジェクトを生成して表示するサンプル(ファイル名:Main.cpp)
#include <iostream>
#include <string>
#include <vector>
#include "StudentInformation.h"

using namespace std;

int main() {
    // オブジェクト作成
    vector<StudentInformation> stdntInfoList;

    StudentInformation obj = StudentInformation();
    obj.setAttendanceNumber(1);
    obj.setName("山田 太郎");
    obj.setDateOfBirth(1993, 4, 8);
    {
        ResultInformation objR = ResultInformation();
        objR.setTestDay(2006, 4, 20);
        objR.setScoreOfJapanese(75);
        objR.setScoreOfEnglish(55);
        obj.getResultInfoList().push_back(objR);

        objR.setTestDay(2006, 9, 15);
        objR.setScoreOfJapanese(89);
        objR.setScoreOfEnglish(45);
        obj.getResultInfoList().push_back(objR);

        objR.setTestDay(2007, 1, 20);
        objR.setScoreOfJapanese(76);
        objR.setScoreOfEnglish(60);
        obj.getResultInfoList().push_back(objR);
    }
    stdntInfoList.push_back(obj);

    obj = StudentInformation();
    obj.setAttendanceNumber(2);
    obj.setName("上野 花子");
    obj.setDateOfBirth(1993, 7, 18);
    {
        ResultInformation objR = ResultInformation();
        objR.setTestDay(2006, 4, 20);
        objR.setScoreOfJapanese(100);
        objR.setScoreOfEnglish(95);
        obj.getResultInfoList().push_back(objR);

        objR.setTestDay(2006, 9, 15);
        objR.setScoreOfJapanese(97);
        objR.setScoreOfEnglish(100);
        obj.getResultInfoList().push_back(objR);

        objR.setTestDay(2007, 1, 20);
        objR.setScoreOfJapanese(95);
        objR.setScoreOfEnglish(98);
        obj.getResultInfoList().push_back(objR);
    }
    stdntInfoList.push_back(obj);

    obj = StudentInformation();
    obj.setAttendanceNumber(3);
    obj.setName("だるま 太郎");
    obj.setDateOfBirth(1993, 12, 1);
    {
        ResultInformation objR = ResultInformation();
        objR.setTestDay(2006, 4, 20);
        objR.setScoreOfJapanese(40);
        objR.setScoreOfEnglish(30);
        obj.getResultInfoList().push_back(objR);

        objR.setTestDay(2006, 9, 15);
        objR.setScoreOfJapanese(45);
        objR.setScoreOfEnglish(35);
        obj.getResultInfoList().push_back(objR);

        objR.setTestDay(2007, 1, 20);
        objR.setScoreOfJapanese(39);
        objR.setScoreOfEnglish(33);
        obj.getResultInfoList().push_back(objR);
    }
    stdntInfoList.push_back(obj);

    obj = StudentInformation();
    obj.setAttendanceNumber(4);
    obj.setName("土野 三郎");
    obj.setDateOfBirth(1994, 3, 4);
    {
        ResultInformation objR = ResultInformation();
        objR.setTestDay(2006, 4, 20);
        objR.setScoreOfJapanese(68);
        objR.setScoreOfEnglish(89);
        obj.getResultInfoList().push_back(objR);

        objR.setTestDay(2006, 9, 15);
        objR.setScoreOfJapanese(60);
        objR.setScoreOfEnglish(90);
        obj.getResultInfoList().push_back(objR);

        objR.setTestDay(2007, 1, 20);
        objR.setScoreOfJapanese(71);
        objR.setScoreOfEnglish(76);
        obj.getResultInfoList().push_back(objR);
    }
    stdntInfoList.push_back(obj);

    // 標準出力
    const char* dateFormat = "%Y/%m/%d";
    char strDate[128] = { 0 };
    cout << "出席番号,名前,生年月日\n";
    cout << "    テスト日,国語の得点,英語の得点,合計得点,平均点\n";
    cout << "==================================================\n";
    for (int i = 0; i < stdntInfoList.size(); i++) {
        const StudentInformation& objRef = stdntInfoList.at(i);
        strftime(strDate, sizeof(strDate) / sizeof(strDate[0]), dateFormat,
                &objRef.getDateOfBirth());
        cout << objRef.getAttendanceNumber() << "," << objRef.getName() << ","
                << strDate << "\n";
        for (int j = 0; j < objRef.getResultInfoList().size(); j++) {
            const ResultInformation& objRRef = objRef.getResultInfoList().at(j);
            strftime(strDate, sizeof(strDate) / sizeof(strDate[0]), dateFormat,
                    &objRRef.getTestDay());
            cout << "    " << strDate << "," << objRRef.getScoreOfJapanese() << ","
                    << objRRef.getScoreOfEnglish() << "," << objRRef.getTotal() << ","
                    << objRRef.getAverage() << "\n";
        }
    }
    return 0;
}
※注意:C++のstd::vectorのpush_back関数は、オブジェクトへの参照を配列に追加するのではなく、実体をコピーします。
なので、ResultInformationオブジェクトの中身を毎回書き換えるなら、ResultInformationオブジェクトの生成は1回だけで済みます。
StudentInformationは、中身を完全には書き換えていない(成績情報リスト)ので、毎度新しくオブジェクトを生成してます。
分かり難いソースで、申し訳ないのですが、C++はそういうものなのです。


実行結果(標準出力)
出席番号,名前,生年月日
    テスト日,国語の得点,英語の得点,合計得点,平均点
==================================================
1,山田 太郎,1993/04/08
    2006/04/20,75,55,130,65
    2006/09/15,89,45,134,67
    2007/01/20,76,60,136,68
2,上野 花子,1993/07/18
    2006/04/20,100,95,195,97.5
    2006/09/15,97,100,197,98.5
    2007/01/20,95,98,193,96.5
3,だるま 太郎,1993/12/01
    2006/04/20,40,30,70,35
    2006/09/15,45,35,80,40
    2007/01/20,39,33,72,36
4,土野 三郎,1994/03/04
    2006/04/20,68,89,157,78.5
    2006/09/15,60,90,150,75
    2007/01/20,71,76,147,73.5

■VBAの場合(動作確認環境:VBA 6.0 )

成績情報クラス(モジュール名:ResultInformation(クラスモジュール))
''
' 成績情報。1件分のデータを保持します。
Option Explicit

'' テスト日
Private m_testDay As Date
'' 国語の得点
Private m_scoreOfJapanese As Integer
'' 英語の得点
Private m_scoreOfEnglish As Integer

''
' テスト日を返します。
' @return テスト日
Public Property Get testDay() As Date
    testDay = m_testDay
End Property

''
' テスト日を設定します。
' @param newTestDay テスト日
Public Property Let testDay(ByVal newTestDay As Date)
    m_testDay = newTestDay
End Property

''
' 国語の得点を返します。
' @return 国語の得点
Public Property Get scoreOfJapanese() As Integer
    scoreOfJapanese = m_scoreOfJapanese
End Property

''
' 国語の得点を設定します。
' @param newScoreOfJapanese 国語の得点
Public Property Let scoreOfJapanese(ByVal newScoreOfJapanese As Integer)
    m_scoreOfJapanese = newScoreOfJapanese
End Property

''
' 英語の得点を返します。
' @return 英語の得点
Public Property Get scoreOfEnglish() As Integer
    scoreOfEnglish = m_scoreOfEnglish
End Property

''
' 英語の得点を設定します。
' @param newScoreOfEnglish 英語の得点
Public Property Let scoreOfEnglish(ByVal newScoreOfEnglish As Integer)
    m_scoreOfEnglish = newScoreOfEnglish
End Property

''
' 合計得点を返します。
' @return 合計得点
Public Property Get total() As Integer
    total = m_scoreOfJapanese + m_scoreOfEnglish
End Property

''
' 平均点を返します。
' @return 平均点
Public Property Get average() As Double
    average = total() / 2#
End Property


成績情報のリストクラス(モジュール名:ResultInformations(クラスモジュール))
''
' 成績情報のリスト。複数のデータを保持します。
Option Explicit

'' 成績情報のリスト
Private m_resultInfoList As New Collection

''
' 件数を返します
' @return 件数
Public Function Count() As Long
    Count = m_resultInfoList.Count()
End Function

''
' 成績情報を返します
' @param index 1以上の要素番号
' @return 成績情報
Public Function Item(ByVal index As Variant) As ResultInformation
    Set Item = m_resultInfoList.Item(index)
End Function

''
' 成績情報を追加します
' @param newItem 追加する成績情報
Public Sub Add(ByVal newItem As ResultInformation)
    Call m_resultInfoList.Add(newItem)
End Sub

''
' 成績情報を削除します
' @param 1以上の要素番号
Public Sub Remove(ByVal index As Variant)
    Call m_resultInfoList.Remove(index)
End Sub


生徒情報クラス(モジュール名:StudentInformation(クラスモジュール))
''
' 生徒情報クラス。1件分のデータを保持します。
Option Explicit

'' 出席番号
Private m_attendanceNumber As Integer
'' 名前
Private m_name As String
'' 生年月日
Private m_dateOfBirth As Date
'' 成績情報のリスト
Private m_resultInfoList As New ResultInformations

''
' 出席番号を返します。
' @return 出席番号
Public Property Get attendanceNumber() As Integer
    attendanceNumber = m_attendanceNumber
End Property

''
' 出席番号を設定します。
' @param newAttendanceNumber 出席番号
Public Property Let attendanceNumber(ByVal newAttendanceNumber As Integer)
    m_attendanceNumber = newAttendanceNumber
End Property

''
' 名前を返します。
' @return 名前
Public Property Get name() As String
    name = m_name
End Property

''
' 名前を設定します。
' @param newName 名前
Public Property Let name(ByVal newName As String)
    m_name = newName
End Property

''
' 生年月日を返します。
' @return 生年月日
Public Property Get dateOfBirth() As Date
    dateOfBirth = m_dateOfBirth
End Property

''
' 生年月日を設定します。
' @param newDateOfBirth 生年月日
Public Property Let dateOfBirth(ByVal newDateOfBirth As Date)
    m_dateOfBirth = newDateOfBirth
End Property

''
' 成績情報のリストを返します。
' @return 成績情報のリスト
Public Property Get resultInfoList() As ResultInformations
    Set resultInfoList = m_resultInfoList
End Property


生徒情報と成績情報オブジェクトを生成して表示するサンプル(モジュール名:Main(標準モジュール))
Option Explicit

Sub main()
    ' オブジェクト作成
    Dim stdntInfoList As New Collection

    Dim obj As StudentInformation
    Dim objR As ResultInformation

    Set obj = New StudentInformation
    obj.attendanceNumber = 1
    obj.name = "山田 太郎"
    obj.dateOfBirth = DateSerial(1993, 4, 8)
    Call stdntInfoList.Add(obj)
        Set objR = New ResultInformation
        objR.testDay = DateSerial(2006, 4, 20)
        objR.scoreOfJapanese = 75
        objR.scoreOfEnglish = 55
        Call obj.resultInfoList.Add(objR)

        Set objR = New ResultInformation
        objR.testDay = DateSerial(2006, 9, 15)
        objR.scoreOfJapanese = 89
        objR.scoreOfEnglish = 45
        Call obj.resultInfoList.Add(objR)

        Set objR = New ResultInformation
        objR.testDay = DateSerial(2007, 1, 20)
        objR.scoreOfJapanese = 76
        objR.scoreOfEnglish = 60
        Call obj.resultInfoList.Add(objR)


    Set obj = New StudentInformation
    obj.attendanceNumber = 2
    obj.name = "上野 花子"
    obj.dateOfBirth = DateSerial(1993, 7, 18)
    Call stdntInfoList.Add(obj)

        Set objR = New ResultInformation
        objR.testDay = DateSerial(2006, 4, 20)
        objR.scoreOfJapanese = 100
        objR.scoreOfEnglish = 95
        Call obj.resultInfoList.Add(objR)

        Set objR = New ResultInformation
        objR.testDay = DateSerial(2006, 9, 15)
        objR.scoreOfJapanese = 97
        objR.scoreOfEnglish = 100
        Call obj.resultInfoList.Add(objR)

        Set objR = New ResultInformation
        objR.testDay = DateSerial(2007, 1, 20)
        objR.scoreOfJapanese = 95
        objR.scoreOfEnglish = 98
        Call obj.resultInfoList.Add(objR)


    Set obj = New StudentInformation
    obj.attendanceNumber = 3
    obj.name = "だるま 太郎"
    obj.dateOfBirth = DateSerial(1993, 12, 1)
    Call stdntInfoList.Add(obj)

        Set objR = New ResultInformation
        objR.testDay = DateSerial(2006, 4, 20)
        objR.scoreOfJapanese = 40
        objR.scoreOfEnglish = 30
        Call obj.resultInfoList.Add(objR)

        Set objR = New ResultInformation
        objR.testDay = DateSerial(2006, 9, 15)
        objR.scoreOfJapanese = 45
        objR.scoreOfEnglish = 35
        Call obj.resultInfoList.Add(objR)

        Set objR = New ResultInformation
        objR.testDay = DateSerial(2007, 1, 20)
        objR.scoreOfJapanese = 39
        objR.scoreOfEnglish = 33
        Call obj.resultInfoList.Add(objR)


    Set obj = New StudentInformation
    obj.attendanceNumber = 4
    obj.name = "土野 三郎"
    obj.dateOfBirth = DateSerial(1994, 3, 4)
    Call stdntInfoList.Add(obj)

        Set objR = New ResultInformation
        objR.testDay = DateSerial(2006, 4, 20)
        objR.scoreOfJapanese = 68
        objR.scoreOfEnglish = 89
        Call obj.resultInfoList.Add(objR)

        Set objR = New ResultInformation
        objR.testDay = DateSerial(2006, 9, 15)
        objR.scoreOfJapanese = 60
        objR.scoreOfEnglish = 90
        Call obj.resultInfoList.Add(objR)

        Set objR = New ResultInformation
        objR.testDay = DateSerial(2007, 1, 20)
        objR.scoreOfJapanese = 71
        objR.scoreOfEnglish = 76
        Call obj.resultInfoList.Add(objR)

    ' イミディエイトに出力
    Const dateFormat As String = "yyyy/M/d"
    Debug.Print "出席番号,名前,生年月日"
    Debug.Print "    テスト日,国語の得点,英語の得点,合計得点,平均点"
    Debug.Print "=================================================="
    Dim i As Integer
    Dim j As Integer
    For i = 1 To stdntInfoList.Count() Step 1
        Set obj = stdntInfoList.Item(i)
        Debug.Print obj.attendanceNumber _
                & "," & obj.name _
                & "," & format(obj.dateOfBirth, dateFormat)
        For j = 1 To obj.resultInfoList().Count() Step 1
            Set objR = obj.resultInfoList().Item(j)
            Debug.Print "    " & format(objR.testDay, dateFormat) _
                    & "," & objR.scoreOfJapanese _
                    & "," & objR.scoreOfEnglish _
                    & "," & objR.total _
                    & "," & objR.average
        Next
    Next
End Sub


実行結果(イミディエイトウィンドウ)
出席番号,名前,生年月日
    テスト日,国語の得点,英語の得点,合計得点,平均点
==================================================
1,山田 太郎,1993/4/8
    2006/4/20,75,55,130,65
    2006/9/15,89,45,134,67
    2007/1/20,76,60,136,68
2,上野 花子,1993/7/18
    2006/4/20,100,95,195,97.5
    2006/9/15,97,100,197,98.5
    2007/1/20,95,98,193,96.5
3,だるま 太郎,1993/12/1
    2006/4/20,40,30,70,35
    2006/9/15,45,35,80,40
    2007/1/20,39,33,72,36
4,土野 三郎,1994/3/4
    2006/4/20,68,89,157,78.5
    2006/9/15,60,90,150,75
    2007/1/20,71,76,147,73.5
Prev Up Next  Top
このページのトップへ

このページの利用によって発生した、いかなる損害について、このホームページの作成者は責任を負いません。
このページの間違いや嘘を見つけた方、このページに書いて欲しい情報がある方はメールをお願いします。

Microsoft 、Windows 、Visual Basic および Excel は米国Microsoft Corporationの米国およびその他の国における登録商標または商標です。
ここではExcel® をエクセル、Visual Basic® for Applications をVBAと表記する場合があります。
Mac 、Mac OS 、Mac OS X は米国Apple Computer,Inc.の登録商標または商標です。
JavaおよびJavaに関する商標は、米国およびその他の国における米国Sun Microsystems, Inc.の商標または登録商標です。
その他、社名および商品名、システム名称などは、一般に各社の商標または登録商標です。

このホームページの作成者はこれらの会社とはいっさい関係がありません。