様々なデータ型の引き渡し

  この例では,108 行目に見るように,11 種類の方法でデータを関数 method に引数として渡しています.
001	/****************************/
002	/* 様々なデータ型の引き渡し */
003	/*      coded by Y.Suganuma */
004	/****************************/
005	#include <iostream>
006	using namespace std;
007	
008	/***********************/
009	/* クラスComplexの定義 */
010	/***********************/
011	class Complex {
012		public:
013			double re, im;
014			int *a;
015							 // コンストラクタ
016			Complex(double re, double im, int x)
017			{
018				this->re   = re;
019				this->im   = im;
020				this->a    = new int [1];
021				this->a[0] = x;
022			}
023	};
024	
025	/*****************************************************/
026	/* 関数の例                                          */
027	/*      a, b, c : int 型                             */
028	/*      ar_11, ar_12 : int 型 1 次元配列             */
029	/*      ar_21, ar_22, ar_23 : int 型 2 次元配列      */
030	/*      cx1, cx2, cx3 : Complex クラスのオブジェクト */
031	/*****************************************************/
032	void method(int a, int *b, int &c, int ar_11[], int *ar_12, int ar_21[][3], int **ar_22, 
	    int *ar_23, Complex cx1, Complex *cx2, Complex &cx3)
033	{
034		a  = 9;
035		*b = 9;
036		c  = 9;
037		ar_11[0] = 99;
038		ar_12[0] = 99;   // *ar_12 = 99;
039		ar_21[1][0] = 999;
040		ar_22[1][0] = 999;
041		ar_23[3] = 999;
042		cx1.im   = 9999;
043		cx1.a[0] = 555;
044		cx2->im  = 9999;
045		cx2->a[0] = 555;
046		cx3.im   = 9999;
047		cx3.a[0] = 555;
048	}
049	
050	/*************/
051	/* main 関数 */
052	/*************/
053	int main()
054	{
055		int a = 1, b = 1, c = 1;
056		int ar_11 [] = {10, 20};
057		int *ar_12 = new int [2];
058		ar_12[0] = 10;
059		ar_12[1] = 20;
060		int ar_21 [][3] = {{100, 200, 300}, {400, 500, 600}};
061		int **ar_22 = new int * [2];
062		for (int i1 = 0; i1 < 2; i1++) {
063			ar_22[i1] = new int [3];
064			for (int i2 = 0; i2 < 3; i2++) {
065				if (i1 == 0)
066					ar_22[i1][i2] = 100 * (i2 + 1);
067				else
068					ar_22[i1][i2] = 100 * (i2 + 4);
069			}
070		}
071		int ar_23 [][3] = {{100, 200, 300}, {400, 500, 600}};
072		Complex cx1(1000, 2000, 3000);
073		Complex cx2(1000, 2000, 3000);
074		Complex cx3(1000, 2000, 3000);
075						// 関数をcall前
076		cout << "   ***関数をcall前***\n";
077		cout << "a = " << a << " b = " << b << " c = " << c << endl;
078		cout << "ar_11[0] = " << ar_11[0] << ", ar_11[1] = " << ar_11[1] << endl;
079		cout << "ar_12[0] = " << ar_12[0] << ", ar_12[1] = " << ar_12[1] << endl;
080		for (int i1 = 0; i1 < 2; i1++) {
081			for (int i2 = 0; i2 < 3; i2++) {
082				if (i2  < 2)
083					cout << "ar_21[" << i1 << "][" << i2 << "] = " << ar_21[i1][i2] << ", ";
084				else
085					cout << "ar_21[" << i1 << "][" << i2 << "] = " << ar_21[i1][i2] << endl;
086			}
087		}
088		for (int i1 = 0; i1 < 2; i1++) {
089			for (int i2 = 0; i2 < 3; i2++) {
090				if (i2  < 2)
091					cout << "ar_22[" << i1 << "][" << i2 << "] = " << ar_22[i1][i2] << ", ";
092				else
093					cout << "ar_22[" << i1 << "][" << i2 << "] = " << ar_22[i1][i2] << endl;
094			}
095		}
096		for (int i1 = 0; i1 < 2; i1++) {
097			for (int i2 = 0; i2 < 3; i2++) {
098				if (i2  < 2)
099					cout << "ar_23[" << i1 << "][" << i2 << "] = " << ar_23[i1][i2] << ", ";
100				else
101					cout << "ar_23[" << i1 << "][" << i2 << "] = " << ar_23[i1][i2] << endl;
102			}
103		}
104		cout << "cx1.re = " << cx1.re << ", cx1.im = " << cx1.im << ", cx1.a[0] = " << cx1.a[0] << endl;
105		cout << "cx2.re = " << cx2.re << ", cx2.im = " << cx2.im << ", cx2.a[0] = " << cx2.a[0] << endl;
106		cout << "cx3.re = " << cx3.re << ", cx3.im = " << cx3.im << ", cx3.a[0] = " << cx3.a[0] << endl;
107						// 関数をcall
108		method(a, &b, c, ar_11, ar_12, ar_21, ar_22, &ar_23[0][0], cx1, &cx2, cx3);
109						// 関数をcall後
110		cout << "   ***関数をcall後***\n";
111		cout << "a = " << a << " b = " << b << " c = " << c << endl;
112		cout << "ar_11[0] = " << ar_11[0] << ", ar_11[1] = " << ar_11[1] << endl;
113		cout << "ar_12[0] = " << ar_12[0] << ", ar_12[1] = " << ar_12[1] << endl;
114		for (int i1 = 0; i1 < 2; i1++) {
115			for (int i2 = 0; i2 < 3; i2++) {
116				if (i2  < 2)
117					cout << "ar_21[" << i1 << "][" << i2 << "] = " << ar_21[i1][i2] << ", ";
118				else
119					cout << "ar_21[" << i1 << "][" << i2 << "] = " << ar_21[i1][i2] << endl;
120			}
121		}
122		for (int i1 = 0; i1 < 2; i1++) {
123			for (int i2 = 0; i2 < 3; i2++) {
124				if (i2  < 2)
125					cout << "ar_22[" << i1 << "][" << i2 << "] = " << ar_22[i1][i2] << ", ";
126				else
127					cout << "ar_22[" << i1 << "][" << i2 << "] = " << ar_22[i1][i2] << endl;
128			}
129		}
130		for (int i1 = 0; i1 < 2; i1++) {
131			for (int i2 = 0; i2 < 3; i2++) {
132				if (i2  < 2)
133					cout << "ar_23[" << i1 << "][" << i2 << "] = " << ar_23[i1][i2] << ", ";
134				else
135					cout << "ar_23[" << i1 << "][" << i2 << "] = " << ar_23[i1][i2] << endl;
136			}
137		}
138		cout << "cx1.re = " << cx1.re << ", cx1.im = " << cx1.im << ", cx1.a[0] = " << cx1.a[0] << endl;
139		cout << "cx2.re = " << cx2.re << ", cx2.im = " << cx2.im << ", cx2.a[0] = " << cx2.a[0] << endl;
140		cout << "cx3.re = " << cx3.re << ", cx3.im = " << cx3.im << ", cx3.a[0] = " << cx3.a[0] << endl;
141		return 0;
142	}
		
1 番目の引数 a

  055 行目で設定された a の値が,032 行目の a にコピーされ,関数 method に渡されます.034 行目において a の値を変更しても,コピーが変更されただけですから,main プログラム内の a の値はそのままです(出力結果の 015 行目参照).

2 番目の引数 &b

  変数 b のアドレスのコピーが関数 method に渡されます.アドレスが指す場所は main プログラムの b そのものですから,035 行目の実行によって,main プログラムにおける b の値も変更されます(出力結果の 015 行目参照).

3 番目の引数 c

  108 行目だけを見る限り,変数 a と同じ渡し方に見えますが,032 行目を見て下さい.このような渡し方を参照渡しと呼びます.036 行目のように,アドレス渡しの場合と変数の参照方法は異なりますが,実際的な効果はアドレスを渡す場合と同様です(出力結果の 015 行目参照).なお,032 行目において,int &c の代わりに const int &c と記述しておけば,値の変更は不可能になります.

4 番目の引数 ar_11

  1 次元配列を渡しています.C/C++ に対する配列とポインタにおいて説明しましたように,配列は,ポインタが記憶領域の先頭アドレスを指しているとみなすことが出来ます.この場合も,記憶領域を指すアドレスが関数 method に渡されます.従って,関数内で記憶領域の値を変更すれば,main プログラム内の配列の値も変化します(出力結果の 016 行目参照).なお,1 次元配列の場合は,032 行目において,int ar_11[] の代わりに int *ar_11 と記述しても構いません.

5 番目の引数 ar_12

  new 演算子で生成した 1 次元配列を渡しています.基本的に,通常の 1 次元配列と同じです(出力結果の 017 行目参照).

6 番目の引数 ar_21

  2 次元配列を渡しています.1 次元配列の場合と同様,記憶領域の先頭を指すアドレスを渡していることになりますが,032 行目の記述に注意して下さい.このプログラムの場合,int ar_21[2][3] と記述すべきところを,行の大きさ 2 を省略し,int ar_21[][3] と記述しています.3 次元以上の配列の場合も同様ですが,省略可能なのは最も左側に相当する要素数だけです.この場合も,当然,main プログラムにおける配列の値が変化しています(出力結果の 018,019 行目参照).

7 番目の引数 ar_22

  new 演算子で生成した 2 次元配列を渡しています.基本的に,通常の 2 次元配列と同じです(出力結果の 020,021 行目参照).ただし,032 行目の記述に注意して下さい.

8 番目の引数 &ar_23[0][0]

  C/C++ に対する配列とポインタにおいて説明しましたように,多次元配列の各要素は連続した領域に確保されますので,それを 1 次元配列として扱うことが可能です.この例では,2 次元配列の先頭のアドレスを渡し,関数側では 1 次元配列として処理しています(041 行目,出力結果の 022,023 行目参照).

9 番目の引数 cx1

  Complex クラスのオブジェクトを渡しています.オブジェクト全体がコピーされ関数に渡されます.従って,関数内でオブジェクト内の値を変更しても,main プログラム内のオブジェクトはその影響を受けませんが,a[0] に関しては,関数内での変更がそのまま反映されています(出力結果の 024 行目参照).これは,オブジェクト全体がコピーされ関数に渡されても,new 演算子を使用している部分は,配列 a のアドレスだけがコピーされ,そのアドレスが指す配列内のデータはコピーされないため,main プログラム内の cx1 と 関数内の cx1 は同じデータを指すことになるからです.

10 番目の引数 &cx2

  Complex クラスのオブジェクトのアドレスを渡しています.従って,関数内で値を変更すると,main プログラム内のオブジェクトの値も変更されます(出力結果の 025 行目参照).

11 番目の引数 cx3

  Complex クラスのオブジェクトに対する参照渡しです.9 番目の引数のような渡し方をすると,オブジェクトが大きい場合,コピーを作成するために多くの時間や領域が必要になります.10 番目の引数のように,アドレスを渡せばその問題は解決しますが,044,045 行目のように,変数の参照方法を変えなくてはなりません.従って,オブジェクトを引数とする場合は,参照渡しが多く使用されます.勿論,期待した結果も得られますし(出力結果の 026 行目参照),値を変更しない場合は,3 番目の引数の項で説明したような const を使用すれば可能です.ただし,new 演算子を使用した配列 a に関しては,const 指定が有効に働きません.
  このプログラムによって,以下に示すような結果が得られます(行番号は説明用に追加).
01	   ***関数をcall前***
02	a = 1 b = 1 c = 1
03	ar_11[0] = 10, ar_11[1] = 20
04	ar_12[0] = 10, ar_12[1] = 20
05	ar_21[0][0] = 100, ar_21[0][1] = 200, ar_21[0][2] = 300
06	ar_21[1][0] = 400, ar_21[1][1] = 500, ar_21[1][2] = 600
07	ar_22[0][0] = 100, ar_22[0][1] = 200, ar_22[0][2] = 300
08	ar_22[1][0] = 400, ar_22[1][1] = 500, ar_22[1][2] = 600
09	ar_23[0][0] = 100, ar_23[0][1] = 200, ar_23[0][2] = 300
10	ar_23[1][0] = 400, ar_23[1][1] = 500, ar_23[1][2] = 600
11	cx1.re = 1000, cx1.im = 2000, cx1.a[0] = 3000
12	cx2.re = 1000, cx2.im = 2000, cx2.a[0] = 3000
13	cx3.re = 1000, cx3.im = 2000, cx3.a[0] = 3000
14	   ***関数をcall後***
15	a = 1 b = 9 c = 9
16	ar_11[0] = 99, ar_11[1] = 20
17	ar_12[0] = 99, ar_12[1] = 20
18	ar_21[0][0] = 100, ar_21[0][1] = 200, ar_21[0][2] = 300
19	ar_21[1][0] = 999, ar_21[1][1] = 500, ar_21[1][2] = 600
20	ar_22[0][0] = 100, ar_22[0][1] = 200, ar_22[0][2] = 300
21	ar_22[1][0] = 999, ar_22[1][1] = 500, ar_22[1][2] = 600
22	ar_23[0][0] = 100, ar_23[0][1] = 200, ar_23[0][2] = 300
23	ar_23[1][0] = 999, ar_23[1][1] = 500, ar_23[1][2] = 600
24	cx1.re = 1000, cx1.im = 2000, cx1.a[0] = 555
25	cx2.re = 1000, cx2.im = 9999, cx2.a[0] = 555
26	cx3.re = 1000, cx3.im = 9999, cx3.a[0] = 555