#include  <iostream>
using namespace std;
// TMU 情報科学科 プログラミング基礎演習

// 課題の指示は，// のコメントに書かれている /**/ の方は無視しても構わないが，参考にしてもらいたい．
double f1(double a)
{
    /* 普通の関数の例．double 型の変数の複製を受取，a に格納して処理を行う関数である
    　　複製なので，この変数に対し行った操作は引数に指定した変数に影響を与えない．
       オブジェクト指向で言えば，この a と 引数の変数が持つオブジェクトは別物である．*/
    a = a + 1;
    return a;
}
double f2(double& a)
{
    /* 参照を受け取る関数. double 型変数の参照を受け取る．この時，複製が作成されるわけではなく，変数の記憶域が共有された状態となる．
       このため，この変数に対し行った操作は，引数に指定された変数の値に影響を及ぼす．
       オブジェクト指向で言えば，この a と 引数の変数が持つオブジェクトは同一である．*/

    // a に 1 を加算．a の値を返すように処理を追加すること
    return a;
}
double f2p(double* a)
{
    /* ポインタを受け取る関数. double 型変数のポインタを受け取る．
       ポインタはオブジェクトの格納場所の情報を持っていて，それは間接参照演算子 * で取得可能である．
       できることは参照渡しと同じであるが，ポインタは危険で，
       毎回 * を適用しなければならず冗長なので，C++ ではオブジェクトに対しては可能な限り参照渡しを使うようにする */

    *a = *a + 1;
    return *a;
}
double& f3(double& a)
{
    /* double 型変数の参照を a で受取，それをそのまま返す関数である．
       この関数はこのままでいい．f4 を作る際の参考にしてもらいたい．*/
    return a;
}

// 関数 f4 を作成する．
//  引数:     double 型変数の参照を一つ
//  戻り値:   受け取った引数の参照
//  処理内容: 引数の値を 1 加算
//  (1)の行で 9 と出力されるように作成すること

class XYZ{
    double x, y, z;
public:
    XYZ(double xa, double ya, double za){
        // メンバ変数の x, y, z をそれぞれ xa, xy, za で初期化すること
    }
    void add(double xa, double ya, double za){
        // メンバ変数の x, y, z にそれぞれ xa, xy, za を加算すること
    }
    double& getRef(int i){
        // i = 1 なら x，i = 2 なら y, i = 3 なら z の参照を返すこと
    }
    friend double sum(XYZ a); // (4)
    // f7 の関数が private メンバ x, y, z を参照できるように，friend 指定をして以下に記述．(4) の sum を参考にすること．
    // f7 や sum はそもそもメンバ関数として実装すれば friend など必要ないのだが，ここでは練習のためにこの実装に取り組むことが望ましい．
};

XYZ& f5(XYZ& a){
    /* いじる必要はない．f6 を作る際の参考にせよ． */
    return a;
}

double sum(XYZ a){
    // (4) で friend が指定されているため，XYZ の private メンバである x, y, z を参照可能
    return a.x + a.y + a.z;
}

// 関数 f6 を作成する．
//    引数:     XYZ 型変数の参照を一つ
//    戻り値:   受け取った引数の参照
//    処理内容: 引数メンバ変数 x, y, z の値を全て 1 加算
//    (2) の行で 9 と出力されるように作成すること

// 関数 f7 を作成する
//    引数:     XYZ 型変数を一つ
//    戻り値:   double 型
//    処理内容:  引数のメンバ x, y, z の積を返す

// 正しい出力を以下に示す．同じになるよう頑張ってもらいたい．
// --- basic type part ---
// 1
// 2
// 1
// 2
// 3
// 4
// 4
// 4
// 4
// 5
// 6
// 9
// --- class part ---
// 9
// 10
// 11
// 9
// 18
// 210

int main()
{
    double x = 1;
    cout << "--- basic type part ---\n";
    cout << x << "\n"; 
    cout << f1(x) << "\n"; 
    cout << x << "\n";
    f2(x); /* equivalent to x = x + 1;*/
    cout << x << "\n"; 
    cout << f2(x) << "\n"; 
    cout << f2p(&x) << "\n"; 
    cout << x << "\n"; 
    f3(x) = 4;  /* equivalent to x = 4;*/
    cout << x << "\n"; 
    cout << f3(x) << "\n"; 
    f3(f3(x)) = 5;  /* equivalent to x = 5;*/
    cout << x << "\n"; 
    f4(x); // equivalent to x = x + 1;
    cout << x << "\n"; 
    f4(f4(f4(x)));  /*  equivalent to x = x + 1; x = x + 1; x = x + 1;*/
    cout << x << "\n"; // (1)

    cout << "--- class part ---\n";
// まずここより上部が正しく実行されるか，最初は以下をコメントアウトするなどして動作を確認したほうが良い．

    XYZ xyz(1,1,1);
    xyz.add(1,1,1);
    f5(xyz).add(7, 8, 9);  /* equivalent to xyz.add(7, 8, 9);*/

    cout << xyz.getRef(1) << "\n"; 
    cout << xyz.getRef(2) << "\n"; 
    cout << xyz.getRef(3) << "\n"; 

    xyz.getRef(1) = 1;
    xyz.getRef(2) = 2;
    xyz.getRef(3) = 3;
    f6(xyz);
    cout << sum(xyz) << "\n"; // (2)
    f6(f6(f6(xyz)));
    cout << xyz.getRef(1) + xyz.getRef(2) + xyz.getRef(3) << "\n"; // (3), sum(xyz) と同値である．参考までに．
    cout << f7(xyz) << "\n"; 
    return 0;
}