情報学部 菅沼ホーム 目次 索引

第8章 変数の有効範囲(スコープ)

    1. A. C++
    2. B. Java
    3. C. JavaScript
    4. D. PHP
    5. E. Ruby
    6. F. Python
    7. G. C#
    8. H. VB

  1. C++

    01	/****************************/
    02	/* 変数の有効範囲(スコープ) */
    03	/*      coded by Y.Suganuma */
    04	/****************************/
    05	#include <stdio.h>
    06	
    07	/*******************/
    08	/* クラス Example1 */
    09	/*******************/
    10	class Example1 {
    11			int pri;
    12		protected :
    13			int pro;
    14		public :
    15			int pub;
    16	
    17			Example1() {
    18				pub = 1000;
    19				pri = 2000;
    20				pro = 3000;
    21			}
    22	
    23			void sub1() {
    24				printf("sub1 pub %d pri %d pro %d\n", pub, pri, pro);
    25			}
    26	};
    27	
    28	/*******************/
    29	/* クラス Example2 */
    30	/*******************/
    31	class Example2 : public Example1 {
    32	
    33		public :
    34	
    35			Example2() {}
    36	
    37			void sub2() {
    38				printf("sub2 pub %d pro %d\n", pub, pro);
    39	//			printf("sub2 pri %d\n", pri);   // 許されない
    40			}
    41	};
    42	
    43	void sub();
    44	
    45	/****************/
    46	/* main program */
    47	/****************/
    48	int main()
    49	{
    50				// ブロック
    51		int x = 10;
    52		if (x > 5) {
    53			printf("block x %d\n", x);
    54			int x = 15;
    55			int y = 20;
    56			printf("block x %d\n", x);
    57			printf("block y %d\n", y);
    58		}
    59		sub();
    60		printf("x %d\n", x);
    61	//	int y = 100;   // この文がなければ,y が未定義
    62	//	printf("y %d\n", y);
    63		extern int z;
    64		printf("z %d\n", z);
    65				// クラス
    66		Example2 ex = Example2();
    67		ex.sub1();
    68		ex.sub2();
    69		printf("public member( pub ) %d\n", ex.pub);
    70	
    71		return 0;
    72	}
    73	
    74	int z = 30;
    75	
    76	/************/
    77	/* 関数 sub */
    78	/************/
    79	void sub()
    80	{
    81		int x = 40;
    82		printf("   sub x %d\n", x);
    83		printf("   sub z %d\n", z);
    84	}
    			
      まず,51 行目において,変数 x が定義され,10 で初期設定されています.この変数 x は,この位置から main 関数が終わる 72 行目まで有効になります.52 ~ 58 行目の if ブロック内の 53 行目において,変数 x の値が出力されていますが,当然,その結果は,51 行目で宣言されたときの値になります.しかし,54 行目において,再び,変数 x が宣言されていますので,この位置から if ブロックの最後である 58 行目までは,ここで宣言された x が有効になります.同様に,55 行目で宣言された変数 y の有効範囲も 58 行目までとなります.実際,60 行目における出力文では,51 行目において宣言された変数 x の値が出力されます.また,61 行目のような型宣言を行わず,62 行目のように変数 y の値を出力しようとすればエラーになってしまいます.

      59 行目において関数 sub を呼んでいます.81 行目では,変数 x を宣言し,82 行目において,その値を出力しています.当然,81 行目の宣言を行わなければ,エラーになってしまいますし,また,81 行目の宣言によって,51 行目で宣言された x の値が影響を受けることはありません( 60 行目の出力文に対応する結果参照).しかし,変数 z は,main 関数内にも,関数 sub 内にも宣言されておらず,すべての関数の外側である 74 行目において宣言されています.このように,関数の外側で宣言された変数をグローバル変数と呼び,すべての関数から参照が可能になります.逆に,変数 x や y のように,あるブロック(関数を含む)内だけで有効な変数を,ローカル変数と呼びます.

      グローバル変数 z が,同じファイル内で,かつ,その変数を参照する前に宣言されていますので,そのまま参照可能ですが( 83 行目),異なるファイルや,参照する場所の後ろで宣言されている場合は,63 行目のような extern 指定が必要になります.以上,51 ~ 64 行目内の出力文(関数 sub 内の出力文を含む)によって,以下に示すような出力が得られます.
    block x 10
    block x 15
    block y 20
       sub x 40
       sub z 30
    x 10
    z 30				
      次に,クラスに付いて考えてみます.10 ~ 26 行目においてクラス Example1 が定義され,31 ~ 41 行目では,クラス Example1 を継承する形で,クラス Example2 が定義されています.31 行目において,public 指定がしてありますので,クラス Example の各変数や関数のアクセス権は,そのままクラス Example2 に引き継がれます.

      66 行目において,Example2 のインスタンス ex を生成し,67 行目では,クラス Example1 から継承した関数 sub1 を通して,3 つの変数を出力しています.このときは,3 つの変数の値がそのまま出力されます.68 行目では,クラス Example2 に追加された関数 sub2 を通して各変数を出力しています.しかし,この場合は,親クラス Example1 の private メンバー変数 pri を参照することができない点に注意してください.また,69 行目のようなクラスの外側からの参照においては,pubulic メンバー変数 pub だけを参照可能です.なお,private 指定は,同じクラス内の関数だけから,protected 指定は,同じクラス,及び,そのクラスを継承したクラスだけから,また,public 指定は,どこからでも参照可能なことを意味します.以上,66 ~ 69 行目内の出力文(クラスのメンバー関数による出力を含む)によって,以下に示すような出力が得られます.
    sub1 pub 1000 pri 2000 pro 3000
    sub2 pub 1000 pro 3000
    public member( pub ) 1000				

  2. Java

    01	/****************************/
    02	/* 変数の有効範囲(スコープ) */
    03	/*      coded by Y.Suganuma */
    04	/****************************/
    05	import java.io.*;
    06	
    07	public class Test {
    08		public static void main(String args[]) throws IOException
    09		{
    10				// ブロック
    11			int x = 10;
    12			if (x > 5) {
    13				System.out.printf("block x %d\n", x);
    14	//			int x = 15;   // 許されない
    15				int y = 20;
    16				System.out.printf("block y %d\n", y);
    17			}
    18			sub();
    19			System.out.printf("x %d\n", x);
    20	//		int y = 100;   // この文がなければ,y が未定義
    21	//		System.out.printf("y %d\n", y);
    22				// クラス
    23					// クラス
    24			Example2 ex = new Example2();
    25			ex.sub1();
    26			ex.sub2();
    27			System.out.printf("public member( pub ) %d\n", ex.pub);
    28		}
    29	
    30		/************/
    31		/* 関数 sub */
    32		/************/
    33		static void sub()
    34		{
    35			int x = 40;
    36			System.out.printf("   sub x %d\n", x);
    37		}
    38	}
    39	
    40	/*******************/
    41	/* クラス Example1 */
    42	/*******************/
    43	class Example1 {
    44	
    45		private int pri;
    46		protected int pro;
    47		public int pub;
    48	
    49		Example1() {
    50			pub = 1000;
    51			pri = 2000;
    52			pro = 3000;
    53		}
    54	
    55		void sub1() {
    56			System.out.printf("sub1 pub %d pri %d pro %d\n", pub, pri, pro);
    57		}
    58	}
    59	
    60	/*******************/
    61	/* クラス Example2 */
    62	/*******************/
    63	class Example2 extends Example1 {
    64		void sub2() {
    65			System.out.printf("sub2 pub %d pro %d\n", pub, pro);
    66	//		System.out.printf("sub2 pri %d\n", pri);   // 許されない
    67		}
    68	}
    			
      まず,11 行目において,変数 x が定義され,10 で初期設定されています.この変数 x は,この位置から main 関数が終わる 28 行目まで有効になります.12 ~ 17 行目の if ブロック内の 13 行目において,変数 x の値が出力されていますが,当然,その結果は,11 行目で宣言されたときの値になります.14 行目において,再び,変数 x を宣言しようとしていますが,C++ とは異なり,Java では,外側のブロックで定義された変数と同じ名前の変数を,その内側のブロックで定義することは許されません(メソッドの外側で定義された変数と同じ名前の変数をメソッド内で定義することは可能).しかし,異なる変数の定義は許されます.15 行目で宣言された変数 y の有効範囲内は,この位置から if ブロックの最後である 17 行目までとなります.実際,20 行目のような型宣言を行わず,21 行目のような出力を行おうとすれば,エラーになってしまいます.

      18 行目において関数 sub を呼んでいます.35 行目では,変数 x を宣言し,36 行目において,その値を出力しています.当然,35 行目の宣言を行わなければ,エラーになってしまいますし,また,35 行目の宣言によって,11 行目で宣言された x の値が影響を受けることはありません( 19 行目の出力文に対応する結果参照).このように,変数 x や y のように,あるブロック(関数を含む)内だけで有効な変数を,ローカル変数と呼びます.以上,11 ~ 19 行目内の出力文(関数 sub 内の出力文を含む)によって,以下に示すような出力が得られます.
    block x 10
    block y 20
       sub x 40
    x 10				
      次に,クラスに付いて考えてみます.43 ~ 58 行目においてクラス Example1 が定義され,63 ~ 68 行目では,クラス Example1 を継承する形で,クラス Example2 が定義されています.24 行目において,Example2 のインスタンス ex を生成し,25 行目では,クラス Example1 から継承した関数 sub1 を通して,3 つの変数を出力しています.このときは,3 つの変数の値がそのまま出力されます.26 行目では,クラス Example2 に追加された関数 sub2 を通して各変数を出力しています.しかし,この場合は,親クラス Example1 の private メンバー変数 pri を参照することができない点に注意してください.また,27 行目のようなクラスの外側からの参照においては,pubulic メンバー変数 pub だけを参照可能です.なお,private 指定は,同じクラス内の関数だけから,protected 指定は,同じクラス,及び,そのクラスを継承したクラスだけから,また,public 指定は,どこからでも参照可能なことを意味します.以上,24 ~ 27 行目内の出力文(関数内の出力文を含む)によって,以下に示すような出力が得られます.
    sub1 pub 1000 pri 2000 pro 3000
    sub2 pub 1000 pro 3000
    public member( pub ) 1000				

  3. JavaScript

      次のいずれか( x が 10 の場合x が 1 の場合)をクリックすれば,ブラウザ上で実行することができます.表示された画面において,「 OK 」ボタンをクリックすると,テキストエリアに,実行結果が表示されます.また,ページのソースを表示すれば,下に示した JavaScript のソースプログラムも表示可能です.

    01	<!DOCTYPE HTML>
    02	<HTML>
    03	<HEAD>
    04		<TITLE>変数の有効範囲(スコープ)</TITLE>
    05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
    06		<SCRIPT TYPE="text/javascript">
    07			/****************************/
    08			/* 変数の有効範囲(スコープ) */
    09			/*      coded by Y.Suganuma */
    10			/****************************/
    11	
    12			str = "";
    13			z   = 30;
    14	
    15			/************************/
    16			/* オブジェクト Example */
    17			/************************/
    18			function Example() {  // class Example {
    19				this.x = 1000;   // constructor() { this.x = 1000; }
    20			}
    21	
    22			Example.prototype.sub = function() {   // sub = function() {
    23				str += "sub member( x ) " + this.x + "\n";
    24			}
    25	
    26			/************/
    27			/* 関数 run */
    28			/************/
    29			function run() {
    30						// ブロック
    31				let x = 10;
    32				var a = 100;
    33				if (x > 5) {
    34	//				str  += "then block x " + x + "\n";   // 許されない
    35					str  += "then block a " + a + "\n";
    36					let x = 15;
    37					if (x > 7) {
    38						let x = 20;   // OK
    39						str  += "then block block x " + x + "\n";
    40					}
    41					var a = 200;
    42					let b = -100;
    43					var y = 20;
    44					str  += "then block x " + x + "\n";
    45					str  += "then block a " + a + "\n";
    46					str  += "then block b " + b + "\n";
    47					str  += "then block y " + y + "\n";
    48				}
    49				else {
    50					str += "else block x " + x + "\n";
    51					str += "else block a " + a + "\n";
    52					x    = -15;
    53					str += "else block x " + x + "\n";
    54				}
    55	//			let x = 100;   // 許されない
    56	//			var a = 300;   // 許される
    57	//			str += "w " + w + "\n";   // 許されない
    58				sub();
    59				str += "w " + w + "\n";   // グローバル変数
    60				str += "x " + x + "\n";
    61				str += "a " + a + "\n";
    62	//			str += "b " + b + "\n";   // 許されない
    63				str += "y " + y + "\n";   // ブロック内の定義が有効
    64				                          // 最初の x が 1 の時は undefined
    65						// オブジェクト
    66				let ex = new Example();
    67				ex.sub();
    68				str += "member( x ) " + ex.x + "\n";
    69					//
    70					// 結果の設定
    71					//
    72				document.getElementById("tx").value = str;
    73			}
    74	
    75			/************/
    76			/* 関数 sub */
    77			/************/
    78			function sub()
    79			{
    80	//			str  += "   sub x " + x + "\n";   // 許されない
    81				let x = 40;
    82				str  += "   sub x " + x + "\n";
    83				str  += "   sub z " + z + "\n";   // グローバル変数
    84				w     = 50;
    85			}
    86		</SCRIPT>
    87	</HEAD>
    88	<BODY  STYLE="font-size:130%">
    89		<P STYLE="text-align:center">
    90			<INPUT TYPE="button" VALUE="OK" onClick="run()" STYLE="font-size:90%"><BR><BR>
    91			<TEXTAREA TYPE="text" ID="tx" COLS="30" ROWS="10" STYLE="font-size: 100%"></TEXTAREA>
    92		</P>
    93	</BODY>
    94	</HTML>
    			
      基本的に,ブロック内( { } で囲まれた部分,関数も含む)で,let を指定して定義すると,ブロック内のその変数が定義された以降で有効になります.また,関数内で,var を指定して定義すると,たとえブロック内で定義したとしても,関数内のその変数が定義された以降で有効になります.これらの変数をローカル変数と呼びます.関数外で定義された変数,または,let や var を付加せずに定義された変数は,グローバル変数と呼ばれ,変数が定義された以降であれば,どこからでも参照可能(有効)になります.ただし,C/C++ や Java の有効範囲とはかなり異なっていますので注意してください.上のプログラム例について説明する前に,プログラムの断片によって,いくつかの確認を行っておきます.

      まず,var について考えてみます.下に示すプログラムの断片において,01 行目の x は,関数外で定義されたグローバル変数です.しかし,03 行目では,01 行目の x は無視され,「 undefined 」が出力されます.確かに,var を使用して定義された変数の有効範囲は定義された以降ですが,その影響は定義されたブロック全体に及び,関数の外側で定義された同じ名前の変数は無視されます.この例の場合は,04 行目の変数 x の定義が,03 行目に影響を与えています(宣言の巻き上がり).また,var に関しては,04 行目,06 行目のように,複数回定義しても許されますが,08 行目の定義は許されません.
    01	x = 10;
    02	function run() {
    03		alert(x);   // undefined
    04		var x = 20;
    05		alert(x);
    06		var x = 30;
    07		alert(x);
    08	//	let x = 40;  // 定義済みエラー
    09		・・・・・
    10	}				
      次に,let について考えてみます.グローバル変数や影響範囲に対する考え方は var の場合と同じですが,下に示すプログラムの断片において,03 行目では,未定義のためエラーになってしまいます.この例の場合も,04 行目の変数 x の定義が,03 行目に影響を与えています(宣言の巻き上がり).また,複数回同じ名前の変数を定義することは許されません.
    01	x = 10;
    02	function run() {
    03	//	alert(x);   // 未定義エラー
    04		let x = 20;
    05		alert(x);
    06	//	let x = 30;  // 定義済みエラー
    07	//	var x = 30;  // 定義済みエラー
    08	}				
      関数内において,同じ名前の変数を var や let を付加して定義しなければ,下に示すプログラムの断片における 01 行目のグローバル変数が有効になります.
    01	x = 10;
    02	function run() {
    03		alert(x);
    04		x = 20;
    05		alert(x);
    06	}				
      では,上の枠内に示したプログラム例についての説明に移ります.まず,31 行目において,let を付加して変数 x が定義され(変数 x に値が代入され),10 で初期設定されています.この変数 x は,この位置から run 関数が終わる 72 行目まで有効になります.以下,この関数内の 50 行目,60 行目に対応する結果は,31 行目で宣言されたときの値になります.ただし,31 行目の変数の値が 5 以下の時は,52 行目の代入文のため,53 行目,60 行目の文によって,変数 x の値として -15 が出力されます.また,関数 sub 内の x は,関数 run 内の x とは全く別の変数ですので,80 行目は変数 x が未定義のためエラーになります.

      31 行目のように,let を付加して定義された変数の有効範囲内では,同じ名前の変数を再定義することはできません( 55 行目).32 行目において var を付加して定義された変数 a の有効範囲も,run 関数が終わる 72 行目までになりますが,56 行目のように再定義することが可能です.そして,この行以降は,ここで設定された値が有効になります.

      上で述べましたように,let を付加して定義された変数の有効範囲内では,同じ名前の変数を再定義することはできませんが,その内側のブロックでは,同じ名前の変数を再定義することができます( 36 行目,38 行目).勿論,var を付加して定義された変数においても再定義可能ですが,ただし,その意味はかなり異なってきます.let を付加した変数の場合,その有効範囲はブロックの最後までですが( 36 行目の x は 47 行目まで,38 行目の x は 39 行目まで,42 行目の b は 47 行目まで),var を付加した変数( 41 行目の a,43 行目の y )の有効範囲は関数の終わりまでとなります.しかし,変数 y は,ブロック内で定義されているため,31 行目の変数 x の値が 5 以下の時は,63 行目の文によって,undefined が出力されます.また,35 行目の文によって,32 行目で設定された a の値が問題なく出力されますが,34 行目は,36 行目の定義が存在するため,未定義によるエラーになってしまいます(宣言の巻き上がり).C/C++ のように,34 行目~ 35 行目では,31 行目で定義された変数 x が有効になると考えがちですので,注意してください.

      12,13 行目に定義されている変数 str,z は,let や var が付加されていませんので,グローバル変数となり,どの関数からも参照可能になります.84 行目に定義されている変数 w も,let や var が付加されていませんので,グローバル変数となります.しかし,57 行目の段階では,まだ関数 sub が呼ばれていませんので,変数 w が未定義のためエラーになります.このような定義方法は非常に紛らわしく,誤りの原因になりかねません.「関数内で使用するローカル変数には必ず let (場合によっては,var )を付加し,グローバル変数は関数外で let や var を付加せずに宣言する」といった規則を守った方が良いと思います.また,ブロック内において,その外側で定義された変数と同じ名前の変数は使用しない方が良いと思います.

      以上,このプログラムを実行すると,63 行目までの文によって,以下に示すような出力が得られます.各行に付加した数字は,対応する文番号です
    		// 31 行目の x が 10 のとき
    35	then block a 100
    39	then block block x 20
    44	then block x 15
    45	then block a 200
    46	then block b -100
    47	then block y 20
    82	   sub x 40
    83	   sub z 30
    59	w 50
    60	x 10
    61	a 200
    63	y 20
    		// 31 行目の x が 1 のとき
    50	else block x 1
    51	else block a 100
    53	else block x -15
    82	   sub x 40
    83	   sub z 30
    59	w 50
    60	x -15
    61	a 100
    63	y undefined				
      次に,オブジェクトについて考えてみます.15 ~ 24 行目において新しいオブジェクトを定義しています.22 ~ 24 行目は,C++ におけるメンバー関数の定義に対応します.オブジェクト内の変数や関数は,すべて public であり,どこからでも参照可能です.なお,クラスに関してもほとんど同じです.上のプログラムにおいて,18,19,22 行目を,コメントのように変更し,かつ,20 行目を 24 行目の後ろに移動すれば,クラスを利用したプログラムになります.勿論,「クラスと継承」において説明したように,クラスの場合は,プロパティやメソッドの前に # を付加することによって,クラスの外部から参照できなくすることが可能です.

      66 行目において,オブジェクト Example のインスタンス ex を生成し,67 行目では,オブジェクト Example 内の関数 sub を通して,変数 x を出力しています.68 行目は,オブジェクトの外から,直接に,変数 x の値を出力した場合です.オブジェクト内の変数や関数は,すべてどこからでも参照可能ですが,「 ex. 」のような部分を付加しなければならず,プログラムの他の部分で同じ名前の変数や関数を使用していてもそれらと識別でき,混乱を防ぐことができます.これが,オブジェクトを使用する最大の利点かもしれません.以上,66 ~ 68 行目内の文によって,以下に示すような出力が得られます.
    sub member( x ) 1000
    member( x ) 1000				

  4. PHP

    01	<?php
    02	
    03		/****************************/
    04		/* 変数の有効範囲(スコープ) */
    05		/*      coded by Y.Suganuma */
    06		/****************************/
    07		
    08		/*******************/
    09		/* クラス Example1 */
    10		/*******************/
    11		class Example1 {
    12			private $pri;
    13			protected $pro;
    14			public $pub;
    15	
    16			function Example1() {
    17				$this->pub = 1000;
    18				$this->pri = 2000;
    19				$this->pro = 3000;
    20			}
    21	
    22			function sub1() {
    23				printf("sub1 pub %d pri %d pro %d\n", $this->pub, $this->pri, $this->pro);
    24			}
    25		}
    26	
    27		/*******************/
    28		/* クラス Example2 */
    29		/*******************/
    30		class Example2 extends Example1 {
    31			function sub2() {
    32				printf("sub2 pub %d pro %d\n", $this->pub, $this->pro);
    33	//			printf("sub2 pri %d\n", $this->pri);   // 許されない
    34			}
    35		}
    36	
    37		/****************/
    38		/* main program */
    39		/****************/
    40				// ブロック
    41		$x = 10;
    42		$z = 30;
    43		if ($x > 5) {
    44			printf("block x %d\n", $x);
    45			$x = 15;
    46			$y = 20;
    47			printf("block x %d\n", $x);
    48			printf("block y %d\n", $y);
    49		}
    50		else {
    51			printf("block x %d\n", $x);
    52			$x = -15;
    53			printf("block x %d\n", $x);
    54		}
    55		sub();
    56		printf("x %d\n", $x);
    57		printf("y %d\n", $y);   // 最初の x が 1 の時は,y が未定義のためエラー
    58				// クラス
    59		$ex = new Example2();
    60		$ex->sub1();
    61		$ex->sub2();
    62		printf("public member( pub ) %d\n", $ex->pub);
    63	
    64		/************/
    65		/* 関数 sub */
    66		/************/
    67		function sub()
    68		{
    69			$x = 40;
    70			printf("   sub x %d\n", $x);
    71			global $z;
    72			printf("   sub z %d\n", $z);
    73		}
    74	
    75	?>
    			
      まず,41 行目において,変数 $x が定義され(変数 $x に値が代入され),10 で初期設定されています.この変数 $x は,この位置から main プログラムが終わる 62 行目まで有効になります.43 ~ 49 行目の if ブロック内の 44 行目において,変数 $x の値が出力されていますが,当然,その結果は,41 行目で宣言されたときの値になります.しかし,45 行目において,再び,変数 $x が宣言されていますが,PHP の場合は,C++ の場合とは異なり,41 行目で宣言された変数 $x に置き換わることになります.従って,ここで宣言された変数 $x の有効範囲は,main プログラムの終わりである 62 行目までになります.実際,56 行目における出力文では,45 行目において宣言された変数 $x の値が出力されます.同様に,46 行目で宣言された変数 $y の有効範囲も 62 行目までとなります.この例では,問題がありませんが,41 行目における変数 $x の初期値を 5 以下に設定すると,50 ~ 54 行目が実行されることになります.そのブロック内では,変数 $y が使用されていませんので,57 行目の出力文はエラーになってしまいます.変数が定義されているか否か(変数に値が代入されているか否か)の見極めが困難である場合も多いと思いますので,十分注意してください.

      55 行目において関数 sub を呼んでいます.69 行目では,変数 $x を宣言し,70 行目において,その値を出力しています.当然,69 行目の宣言を行わなければ,エラーになってしまいますし,また,69 行目の宣言によって,45 行目で宣言された $x の値が影響を受けることはありません( 56 行目に対応する出力結果参照).しかし,変数 $z は,関数 sub 内に宣言されておらず,42 行目において宣言されています.上で述べた変数 $x と同様,関数内において,main プログラムや他の関数内の変数を参照することはできません.しかし,71 行目の記述( global )によって,main プログラム内の変数を参照可能になります.このように,関数の外側で宣言された変数を関数内から参照可能にした変数をグローバル変数と呼びます.逆に,変数 $x や $y のように,あるブロック(関数を含む)内だけで有効な変数を,ローカル変数と呼びます.以上,41 ~ 57 行目内の出力文(関数 sub 内の出力文を含む)によって,以下に示すような出力が得られます.
    block x 10
    block x 15
    block y 20
       sub x 40
       sub z 30
    x 15
    y 20				
      次に,クラスに付いて考えてみます.11 ~ 25 行目においてクラス Example1 が定義され,30 ~ 35 行目では,クラス Example1 を継承する形で,クラス Example2 が定義されています.PHP においては,クラス Example の各変数や関数のアクセス権は,そのままクラス Example2 に引き継がれます.

      59 行目において,Example2 のインスタンス $ex を生成し,60 行目では,クラス Example1 から継承した関数 sub1 を通して,3 つの変数を出力しています.このときは,3 つの変数の値がそのまま出力されます.61 行目では,クラス Example2 に追加された関数 sub2 を通して各変数を出力しています.しかし,この場合は,親クラス Example1 の private メンバー変数 $pri を参照することができない点に注意してください.また,62 行目のようなクラスの外側からの参照においては,public メンバー変数 $pub だけを参照可能です.なお,private 指定は,同じクラス内の関数だけから,protected 指定は,同じクラス,及び,そのクラスを継承したクラスだけから,また,public 指定は,どこからでも参照可能なことを意味します.以上,59 ~ 62 行目内の出力文によって,以下に示すような出力が得られます.
    sub1 pub 1000 pri 2000 pro 3000
    sub2 pub 1000 pro 3000
    public member( pub ) 1000				

  5. Ruby

    01	#***************************/
    02	# 変数の有効範囲(スコープ) */
    03	#      coded by Y.Suganuma */
    04	#***************************/
    05	
    06	#******************/
    07	# クラス Example1 */
    08	#******************/
    09	class Example1
    10		Const    = 1000;
    11		@@_class = 2000;
    12	
    13		def initialize
    14			@_pro = 3000;
    15		end
    16	
    17		def sub1()
    18			printf("sub1 Const %d @@_class %d @_pro %d\n", Const, @@_class, @_pro);
    19		end
    20	end
    21	
    22	#******************/
    23	# クラス Example2 */
    24	#******************/
    25	class Example2 < Example1
    26		public
    27			def sub2()
    28				printf("sub2 Const %d @@_class %d @_pro %d\n", Const, @@_class, @_pro);
    29			end
    30	
    31		attr_accessor("_pro");
    32	end
    33	
    34	#***********/
    35	# 関数 sub */
    36	#***********/
    37	def sub()   # この位置で定義する必要がある
    38		x = 40;
    39		printf("   sub x %d\n", x);
    40		printf("   sub z %d\n", $z);
    41	end
    42	
    43	#***************/
    44	# main program */
    45	#***************/
    46			# ブロック
    47	x  = 10;
    48	$z = 30;
    49	if x > 5
    50		printf("block x %d\n", x);
    51		x = 15;
    52		y = 20;
    53		printf("block x %d\n", x);
    54		printf("block y %d\n", y);
    55	else
    56		printf("block x %d\n", x);
    57		x = -15;
    58		printf("block x %d\n", x);
    59	end
    60	sub();
    61	printf("x %d\n", x);
    62	printf("y %d\n", y);   # 最初の x が 1 の時は,y が未定義のためエラー
    63			# クラス
    64	ex = Example2.new;
    65	ex.sub1();
    66	ex.sub2();
    67	printf("public member( Const ) %d\n", Example2::Const);
    68	printf("public member( @_pro ) %d\n", ex._pro);
    			
      まず,47 行目において,変数 x が定義され(変数 x に値が代入され),10 で初期設定されています.この変数 x は,この位置から main プログラムが終わる 68 行目まで有効になります.50 ~ 54 行目の if ブロック内の 50 行目において,変数 x の値が出力されていますが,当然,その結果は,47 行目で宣言されたときの値になります.しかし,51 行目において,再び,変数 x が宣言されていますが,Ruby の場合は,C++ の場合とは異なり,47 行目で宣言された変数 x に置き換わることになります.従って,ここで宣言された変数 x の有効範囲は,main プログラムの終わりである 68 行目までになります.実際,61 行目における出力文では,51 行目において宣言された変数 x の値が出力されます.同様に,52 行目で宣言された変数 y の有効範囲も 68 行目までとなります.この例では,問題がありませんが,47 行目における変数 x の初期値を 5 以下に設定すると,56 ~ 58 行目が実行されることになります.そのブロック内では,変数 y が使用されていませんので,62 行目の出力文はエラーになってしまいます.変数が定義されているか否か(変数に値が代入されているか否か)の見極めが困難である場合も多いと思いますので,十分注意してください.

      60 行目において関数 sub を呼んでいます.38 行目では,変数 x を宣言し,39 行目において,その値を出力しています.当然,38 行目の宣言を行わなければ,エラーになってしまいますし,また,38 行目の宣言によって,51 行目で宣言された x の値が影響を受けることはありません( 61 行目の出力文に対応する結果参照).しかし,変数 $z は関数 sub 内に宣言されておらず,main プログラムの 48 行目において宣言されています.このように,名前が $ で始まる変数はグローバル変数と呼ばれ,すべての関数等から参照が可能になります.逆に,変数 x や y のように,あるブロック(関数を含む)内だけで有効な変数を,ローカル変数と呼びます.以上,47 ~ 62 行目内の出力文(関数 sub 内の出力文を含む)によって,以下に示すような出力が得られます.
    block x 10
    block x 15
    block y 20
       sub x 40
       sub z 30
    x 15
    y 20				
      次に,クラスに付いて考えてみます.09 ~ 20 行目においてクラス Example1 が定義され,25 ~ 32 行目では,クラス Example1 を継承する形で,クラス Example2 が定義されています.Ruby においては,クラス Example の各変数や関数のアクセス権は,そのままクラス Example2 に引き継がれます.

      64 行目において,Example2 のインスタンス ex を生成し,65 行目では,クラス Example1 から継承した関数 sub1 を通して,3 つの変数を出力しており,3 つの変数の値がそのまま出力されます.また,66 行目では,クラス Example2 に追加された関数 sub2 を通して各変数を出力しています.Ruby においては,大文字で始まる変数名は,定数とみなされ,クラスの外からも 67 行目のような形で参照可能です.また,@@ で始まるる変数名は,クラス変数と呼ばれ,クラス及びそのサブクラスで共通の値を持ちます.ただし,クラスの外からは,参照することはできません.さらに,@ で始まる変数は,インスタンス変数と呼ばれ,各インスタンス毎に異なる値を持つことができます.C++ における private 指定されたメンバー変数に似ています.そのため,そのままの状態では,クラスの外部から参照することはできません.しかし,31 行目のような指定( attr_accessor )を行うことによって,68 行目のような形でクラス外部から参照可能になります.以上,64 ~ 68 行目内の出力文によって,以下に示すような出力が得られます.
    sub1 Const 1000 @@_class 2000 @_pro 3000
    sub2 Const 1000 @@_class 2000 @_pro 3000
    public member( Const ) 1000
    public member( @_pro ) 3000				

  6. Python

    01	# -*- coding: UTF-8 -*-
    02	
    03	#***************************/
    04	# 変数の有効範囲(スコープ) */
    05	#      coded by Y.Suganuma */
    06	#***************************/
    07	
    08	#******************/
    09	# クラス Example1 */
    10	#******************/
    11	class Example1 :
    12		c_var = 1000
    13	
    14		def __init__(self) :
    15			self.i_var = 2000
    16	
    17		def sub1(self) :
    18			print("sub1 c_var", self.c_var, "i_var", self.i_var)
    19	
    20	#******************/
    21	# クラス Example2 */
    22	#******************/
    23	class Example2(Example1) :
    24		def sub2(self) :
    25			print("sub2 c_var", self.c_var, "i_var", self.i_var)
    26	
    27	#***********/
    28	# 関数 sub */
    29	#***********/
    30	def sub() :   # この位置で定義する必要がある
    31		x = 40
    32		print("   sub x", x)
    33		print("   sub z", z)
    34	
    35	#***************/
    36	# main program */
    37	#***************/
    38			# ブロック
    39	x = 10
    40	z = 30
    41	if x > 5 :
    42		print("block x", x)
    43		x = 15
    44		y = 20
    45		print("block x", x)
    46		print("block y", y)
    47	else :
    48		print("block x", x)
    49		x = -15
    50		print("block x", x)
    51	sub()
    52	print("x", x)
    53	print("y", y)   # 最初の x が 1 の時は,y が未定義のためエラー
    54			# クラス
    55	ex = Example2()
    56	ex.sub1()
    57	ex.sub2()
    58	print("member( c_var )", Example2.c_var)
    59	print("member( i_var )", ex.i_var)
    			
      まず,39 行目において,変数 x が定義され(変数 x に値が代入され),10 で初期設定されています.この変数 x は,この位置から main プログラムが終わる 59 行目まで有効になります.42 ~ 46 行目の if ブロック内の 42 行目において,変数 x の値が出力されていますが,当然,その結果は,39 行目で宣言されたときの値になります.しかし,43 行目において,再び,変数 x が宣言されていますが,Python の場合は,C++ の場合とは異なり,39 行目で宣言された変数 x に置き換わることになります.従って,ここで宣言された変数 x の有効範囲は,main プログラムの終わりである 59 行目までになります.実際,52 行目における出力文では,43 行目において宣言された変数 x の値が出力されます.同様に,44 行目で宣言された変数 y の有効範囲も 59 行目までとなります.この例では,問題がありませんが,39 行目における変数 x の初期値を 5 以下に設定すると,48 ~ 50 行目が実行されることになります.そのブロック内では,変数 y が使用されていませんので,53 行目の出力文はエラーになってしまいます.変数が定義されているか否か(変数に値が代入されているか否か)の見極めが困難である場合も多いと思いますので,十分注意してください.

      51 行目において関数 sub を呼んでいます.31 行目では,変数 x を宣言(変数 x に値を代入)し,32 行目において,その値を出力しています.31 行目の宣言を行わなければ,変数 z と同様,main プログラム内の変数 x の値が出力されます.main プログラム内の変数 x ( 39 行目)の値を変更したい場合は,31 行目の前に,
    global x				
    という宣言をしておく必要があります.

      一般に,Python では,main プログラム内の変数は,33 行目に示すように,どの関数からも参照することができます(非常に危険だと思いますが).ただし,関数内で main プログラムと同じ変数を定義(変数に代入を行うことを意味する)したり,あるいは,新しい変数を定義した場合,それらの変数を main プログラムから参照することはできません( 52 行目に対応する出力結果参照).また,ある関数から,異なる関数内の変数を参照することも不可能です.このように,どの関数からも参照可能な変数をグローバル変数と呼びます.逆に,ある関数内だけで有効な変数を,ローカル変数と呼びます.以上,40 ~ 54 行目内の出力文(関数 sub 内の出力文を含む)によって,以下に示すような出力が得られます.
    block x 10
    block x 15
    block y 20
       sub x 40
       sub z 30
    x 15
    y 20				
      次に,クラスに付いて考えてみます.11 ~ 18 行目においてクラス Example1 が定義され,23 ~ 25 行目では,クラス Example1 を継承する形で,クラス Example2 が定義されています.なお,Python においては,すべての変数をクラス外から参照可能です( C++ において,public 指定してる状況).

      55 行目において,Example2 のインスタンス ex を生成し,56 行目では,クラス Example1 から継承した関数 sub1 を通して,2 つの変数を出力しています.また,57 行目では,クラス Example2 に追加された関数 sub2 を通して各変数を出力しています.いずれも,同じように出力されます.Python において,12 行目のような形で宣言された変数はクラス変数と呼ばれ,すべてのクラスのインスタンスで同じ値を持ち,クラス外部からでも,58 行目のような形で参照できます.また,15 行目のように,self を付加して宣言した変数は,インスタンス変数と呼ばれ,インスタンス毎に異なる値をとることが可能です.インスタンス変数は,59 行目のような形で,クラスの外部からも参照することができます.以上,55 ~ 69 行目内の出力文によって,以下に示すような出力が得られます.
    sub1 c_var 1000 i_var 2000
    sub2 c_var 1000 i_var 2000
    member( c_var ) 1000
    member( i_var ) 2000				

  7. C#

    01	/******************************/
    02	/* 変数の有効範囲(スコープ) */
    03	/*      coded by Y.Suganuma   */
    04	/******************************/
    05	using System;
    06	
    07	class Program
    08	{
    09		static void Main()
    10		{
    11				// ブロック
    12			int x = 10;
    13			if (x > 5) {
    14				Console.WriteLine("block x " + x);
    15	//			int x = 15;   // 許されない
    16				int y = 20;
    17				Console.WriteLine("block y " + y);
    18			}
    19			sub();
    20			Console.WriteLine("x " + x);
    21	//		int y = 100;   // 16 行目がエラー
    22	//		Console.WriteLine("y " + y);   // y が未定義
    23				// クラス
    24					// クラス
    25			Example2 ex = new Example2();
    26			ex.sub1();
    27			ex.sub2();
    28			Console.WriteLine("public member( pub ) " + ex.pub);
    29		}
    30	
    31		/************/
    32		/* 関数 sub */
    33		/************/
    34		static void sub()
    35		{
    36			int x = 40;
    37			Console.WriteLine("   sub x " + x);
    38		}
    39	}
    40	
    41	/*******************/
    42	/* クラス Example1 */
    43	/*******************/
    44	class Example1 {
    45	
    46		private int pri;
    47		protected int pro;
    48		public int pub;
    49	
    50		public Example1() {
    51			pub = 1000;
    52			pri = 2000;
    53			pro = 3000;
    54		}
    55	
    56		public void sub1() {
    57			Console.WriteLine("sub1 pub " + pub + " pri " + pri + " pro " + pro);
    58		}
    59	}
    60	
    61	/*******************/
    62	/* クラス Example2 */
    63	/*******************/
    64	class Example2 : Example1 {
    65		public void sub2() {
    66			Console.WriteLine("sub2 pub " + pub + " pro " + pro);
    67	//		Console.WriteLine("sub2 pri " + pri);   // 許されない
    68		}
    69	}
    			
      まず,12 行目において,変数 x が定義され,10 で初期設定されています.この変数 x は,この位置から main 関数が終わる 28 行目まで有効になります.13 ~ 18 行目の if ブロック内の 15 行目において,再び,変数 x を宣言しようとしていますが,C++ とは異なり,C# では,外側のブロックで定義された変数と同じ名前の変数を,その内側のブロックで定義することは許されません.しかし,異なる変数の定義は許されます.16 行目で宣言された変数 y の有効範囲内は,この位置から if ブロックの最後である 17 行目までとなります.実際,22 行目のような出力を行おうとすれば,変数 y が未定義のためエラーになってしまいます.しかし,21 行目を追加すると,内側のブロックで同じ名前の変数を定義したという理由のため,16 行目でエラーになってしまいます.確かに,21 行目の変数 y の有効範囲はこの行以降ですが,定義などに対する影響はブロック全体に及ぶようです.余りにも怪しげな仕様です.

      19 行目において関数 sub を呼んでいます.36 行目では,変数 x を宣言し,37 行目において,その値を出力しています.当然,36 行目の宣言を行わなければ,エラーになってしまいますし,また,36 行目の宣言によって,12 行目で宣言された x の値が影響を受けることはありません( 20 行目の出力文に対応する結果参照).このように,変数 x や y のように,あるブロック(関数を含む)内だけで有効な変数を,ローカル変数と呼びます.以上,12 ~ 20 行目内の出力文(関数 sub 内の出力文を含む)によって,以下に示すような出力が得られます.
    block x 10
    block y 20
       sub x 40
    x 10				
      次に,クラスに付いて考えてみます.44 ~ 59 行目においてクラス Example1 が定義され,64 ~ 69 行目では,クラス Example1 を継承する形で,クラス Example2 が定義されています.25 行目において,Example2 のインスタンス ex を生成し,26 行目では,クラス Example1 から継承した関数 sub1 を通して,3 つの変数を出力しています.このときは,3 つの変数の値がそのまま出力されます.27 行目では,クラス Example2 に追加された関数 sub2 を通して各変数を出力しています.しかし,この場合は,親クラス Example1 の private メンバー変数 pri を参照することができない点に注意してください.また,28 行目のようなクラスの外側からの参照においては,pubulic メンバー変数 pub だけを参照可能です.なお,private 指定は,同じクラス内の関数だけから,protected 指定は,同じクラス,及び,そのクラスを継承したクラスだけから,また,public 指定は,どこからでも参照可能なことを意味します.以上,25 ~ 28 行目内の出力文(関数内の出力文を含む)によって,以下に示すような出力が得られます.
    sub1 pub 1000 pri 2000 pro 3000
    sub2 pub 1000 pro 3000
    public member( pub ) 1000				

  8. VB

    01	''''''''''''''''''''''''''''
    02	' 変数の有効範囲(スコープ) '
    03	'      coded by Y.Suganuma '
    04	''''''''''''''''''''''''''''
    05	Imports System
    06	Module Test
    07		Sub Main()
    08				' ブロック
    09			Dim x As Integer = 10
    10	'		Dim X As Integer = 100   大文字,小文字を区別しない
    11			If x > 5 Then
    12				Console.WriteLine("block x " & x)
    13				x = 15
    14	'			Dim x As Integer = 15   ' 許されない
    15				Dim y As Integer = 20
    16				Console.WriteLine("block y " & y)
    17			End If
    18			func()
    19			Console.WriteLine("x " & x)
    20	'		Dim y As Integer = 100   ' 14 行目がエラー
    21	'		Console.WriteLine("y %d\n", y)   ' y が未定義
    22				' クラス
    23					' クラス
    24			Dim ex As new Example2()
    25			ex.sub1()
    26			ex.sub2()
    27			Console.WriteLine("public member( pub ) " & ex.pub)
    28		End Sub
    29	
    30		'''''''''''''
    31		' 関数 func '
    32		'''''''''''''
    33		Sub func()
    34			Dim x As Integer = 40
    35			Console.WriteLine("   func x " & x)
    36		End Sub
    37	
    38		'''''''''''''''''''
    39		' クラス Example1 '
    40		'''''''''''''''''''
    41		Class Example1
    42	
    43			Private pri As Integer
    44			Protected pro As Integer
    45			Public pub As Integer
    46	
    47			Sub New ()
    48				pub = 1000
    49				pri = 2000
    50				pro = 3000
    51			End Sub
    52	
    53			Sub sub1()
    54				Console.WriteLine("sub1 pub " & pub & " pri " & pri & " pro " &  pro)
    55			End Sub
    56		End Class
    57	
    58		'''''''''''''''''''
    59		' クラス Example2 '
    60		'''''''''''''''''''
    61		Class Example2
    62			Inherits Example1
    63			Sub sub2()
    64				Console.WriteLine("sub2 pub " & pub & " pro " & pro)
    65	'			Console.WriteLine("sub2 pri " & pri)   ' 許されない
    66			End sub
    67		End Class
    68	End Module
    			
      まず,09 行目において,変数 x が定義され,10 で初期設定されています.この変数 x は,この位置から main 関数が終わる 28 行目まで有効になります.11 ~ 17 行目の if ブロック内の 14 行目において,再び,変数 x を宣言しようとしていますが,C++ とは異なり,VB では,外側のブロックで定義された変数と同じ名前の変数を,その内側のブロックで定義することは許されません.しかし,異なる変数の定義は許されます.15 行目で宣言された変数 y の有効範囲内は,この位置から if ブロックの最後である 16 行目までとなります.実際,21 行目のような出力を行おうとすれば,変数 y が未定義のためエラーになってしまいます.しかし,20 行目を追加すると,内側のブロックで同じ名前の変数を定義したという理由のため,15 行目でエラーになってしまいます.確かに,20 行目の変数 y の有効範囲はこの行以降ですが,定義などに対する影響はブロック全体に及ぶようです.余りにも怪しげな仕様です.

      18 行目において関数 func を呼んでいます.34 行目では,変数 x を宣言し,35 行目において,その値を出力しています.当然,34 行目の宣言を行わなければ,エラーになってしまいますし,また,34 行目の宣言によって,09 行目で宣言された x の値が影響を受けることはありません( 19 行目の出力文に対応する結果参照).このように,変数 x や y のように,あるブロック(関数を含む)内だけで有効な変数を,ローカル変数と呼びます.以上,09 ~ 19 行目内の出力文(関数 sub 内の出力文を含む)によって,以下に示すような出力が得られます.
    block x 10
    block y 20
       func x 40
    x 15				
      次に,クラスに付いて考えてみます.41 ~ 56 行目においてクラス Example1 が定義され,61 ~ 67 行目では,クラス Example1 を継承する形で,クラス Example2 が定義されています.24 行目において,Example2 のインスタンス ex を生成し,25 行目では,クラス Example1 から継承した関数 sub1 を通して,3 つの変数を出力しています.このときは,3 つの変数の値がそのまま出力されます.26 行目では,クラス Example2 に追加された関数 sub2 を通して各変数を出力しています.しかし,この場合は,親クラス Example1 の Private メンバー変数 pri を参照することができない点に注意してください.また,27 行目のようなクラスの外側からの参照においては,Pubulic メンバー変数 pub だけを参照可能です.なお,Private 指定は,同じクラス内の関数だけから,Protected 指定は,同じクラス,及び,そのクラスを継承したクラスだけから,また,Public 指定は,どこからでも参照可能なことを意味します.以上,24 ~ 27 行目内の出力文(関数内の出力文を含む)によって,以下に示すような出力が得られます.
    sub1 pub 1000 pri 2000 pro 3000
    sub2 pub 1000 pro 3000
    public member( pub ) 1000				

情報学部 菅沼ホーム 目次 索引