第5章         関数と手続き

 

【学習内容とねらい】

 

今、あるテストの成績処理プログラムを作成する場合を考えましょう。前章の制御命令をマスターしていれば、基本的にこのプログラムを作成することはできます。しかし、「まずデータをファイルから読み込む部分を作って、それから平均値と標準偏差を計算しよう。おっと平均値を計算するには、得点の総合計と受験者総数が必要だから、それらを先に求めておかないと・・・。そうそう、標準偏差を計算するには偏差の2乗の和を求めておかなければならなかった・・・。」等々と、必要になる処理を逐一思いつくままに書き連ねて行くとミスも多く、また全体構造が分かりずらいプログラムになってしまいます。

 

そこで、以下のように2段階に分けてプログラミングできたらどうでしょうか?

T.このプログラムは以下の処理から成る。

U.各処理の詳細は以下の通り。

(1)   成績データの読み込み

(2)   統計量(平均値と標準偏差)の計算

(3)   成績順の並べ替え(ソート)

(4)   結果の表示

(1)     ・・・

(2)     ・・・

(3)     ・・・

(4)     ・・・

 こうしておけば、Tを見ればプログラム全体の流れが分かります。また、もしソート結果が一部間違っていたとすると、Uの(3)の部分のみを点検すればよく、エラーの発見や修正が容易になります。また、のちに、偏差値も計算することになった場合には、Uの(2)の部分に計算部分を追加するだけですみ、拡張が容易になります。

 

この(1)(4)のような部分処理を「モジュール」といいます。C++Builderでは、モジュールとして「関数」が用意されていますが、本章では「関数」の用い方の学習を通じ、全体のプログラムを「モジュールの組み合わせ」という形で(上の例のように)作成する術を学びます。モジュールは幅広い概念ですが、ここでは「関数」を指していると考えて結構です。

プログラミング学習の成果は、ある処理を自分でモジュールに分割できるかどうか、にかかっていると言われています。その意味で本章はプログラミング入門編の集大成になります。

<本章の構成>

 


5−1  モジュール (1) −2つのボタンからなるプログラム−

5−2  モジュール (2) −1つのボタンですます−

5−3  モジュール (3) −押せないボタンはいらないのか−

5−4  モジュール (4) −構造のはっきりしたプログラム−

5−5  モジュール (5) Button1 Button1 は本当にいらないのか−

5−6  モジュール (6) −プログラムの構造−

5−7  モジュール (7) −戻り値のない「関数」を作ろう−

5−8  関数 (1) −戻り値のある「関数」−

5−9  関数 (2) −絶対値関数を使う−

5−10 関数 (3) −関数を使う−

5−11 関数 (4) random関数−

5−12 ローカル変数とグローバル変数

5−13 メソッド


5-1 モジュール (1) ―2つのボタンからなるプログラム―

【基礎課題 5-1-1

 

文法と会話の得点合計を求めてから合否を判定するプログラムを作りましょう。

ここに後の説明の都合上、二つの「ボタン」コンポーネントのNameプロパティはそれぞれ「Button1」および「Button2」として下さい。


右のようなフォームを持つプログラムを作って下さい。



 

 

 

文法と会話の得点を入力してから「合計点を計算する」ボタンを押すと



 

合計点が計算され、さらに「合否を判定する」ボタンを押すと


 

 

 

150点以上か否かに応じて、合否を判定する。

 

このプログラムは今までの学習範囲内で作成できるはずです。


5-2 モジュール (2) ―1つのボタンですます―

【練習問題】

ボタンを2回押さずに、1回ですます方法があります。フォームの下の方を少しだけ大きくして、第三のボタン「両方のボタンを押す」を付け加えて下さい(Nameプロパティは「Button3」)。



第三のボタンを押したときの処理(イベントハンドラ)は、次のように書いて下さい。

 


void__fastcall TForm1::Button3Click(TObject *Sender)

{

  Button1Click(Sender); // ボタン1を押せ

  Button2Click(Sender); // ボタン2を押せ 

}

 

少し腑に落ちないかもしれませんが、とりあえず実行してみましょう。
「文法」と「会話」の得点を入力してから、第三のボタンを押してみて、プログラムの動作を確かめましょう。

 

「合計点を計算する」ボタンも「合否を判定する」ボタンも使わなくてすみました
それなら、この2つのボタンを見えなくしたらどうなるでしょう。

 

「合計点を計算する」ボタンおよび「合否を判定する」ボタンのVisibleプロパティをFalseにして下さい。

予想 さて、ここで実行ボタンを押す前に、予想をして下さい。

1.       エラーが出て実行できない

2.       エラーは出ないが、目的通りの動作はしない

3.       エラーは出ず、目的通りの動作をする


あなたの予想は         

予想をしたら、実行ボタンを押してプログラムの動作を確かめましょう。

5-3 モジュール (3) ―押せないボタンはいらないのか―

【練習問題】

「合計点を計算する」ボタンと「合否を判定する」ボタン を両方見えなくしても、プログラムは目的通りに動いと思います。


それならば、この2つのボタンをなくしてしまったらどうなるでしょう。


消したいボタンを選択して、


DELキーを押すと


ボタンが消えます。

 

 

 

 

 

 

 

 

 

もう一つのボタンも消しましょう。


予想 さて、ここで実行ボタンを押す前に、予想をして下さい。

1.       エラーが出て実行できない

2.       エラーは出ないが、目的通りの動作はしない

3.       エラーは出ず、目的通りの動作をする


あなたの予想は         

予想をしたら、実行ボタンを押してプログラムの動作を確かめましょう。

 

 


5-4 モジュール (4) ―構造のはっきりしたプログラム―

 

今度は、3科目の合計点を計算してから、合否を判定するプログラムを作ります。

 

【基礎課題 5-4-1】

下のようなフォームを持つプログラムを作って下さい。

 

主なコンポーネントのNameプロパティは、次のようにして下さい。

コンポーネント

Name

ボタン「合計点を計算する」

Button1

ボタン「合否を判定する」

Button2


まず、それぞれのボタンに対して、それを押したときのイベントハンドラを書いて、プログラムが正しく動作するようにして下さい。


 

 

 

 

 


正しく動作することが確認できたら、第三のボタンを付け加えて、そのボタンを押したときの処理を以下のように書いてください。

 

 


void__fastcall TForm1::Button3Click(TObject *Sender)

{

  Button1Click(Sender); // ボタン1を押せ

  Button2Click(Sender); // ボタン2を押せ 

}


最後に、フォームの上にある「合計点を計算する」ボタンと「合否を判定する」ボタンを削除してから、動作を確認してください。

 

前節同様、うまく動作するはずです。

 


5-5 モジュール (5) ―Button1とButton2は本当にいらないのか―

 

前節までの学習で分かった通り、最終的には「Button1」と「Button2」は必要ないようです。なぜなら削除してしまっても、きちんと動作するのですから・・・。ただ、Button1Click」および「Button2Click」のイベントハンドラがあれば、うまく行きそうです。

 

ところで、もはやボタンはなくなりしたがってクリックもできないのですから、Button1Click」や「Button2Click」という名称は実態に合いませんね。そこで、機能が分かるようにButton1Clickを「Keisan」に、Button2Clickを「Hantei」に変えてみましょう。

 

 

 

 

実は、「Button1Click」などの名称変更はこれだけでは不十分です。3-14で開いた「ヘッダーファイル」にも、「Button1Click」などの名称が登録されています。そこで、コードエディタ上で右ボタンクリックし、開いたメニューから「ソース/ヘッダー ファイルを開く」を選択してください。ここで、下の2カ所の名称を変更します。

 

 


予想 さて、ここで実行ボタンを押す前に、予想をして下さい。

1.       エラーが出て実行できない

2.       エラーは出ないが、目的通りの動作はしない

3.       エラーは出ず、目的通りの動作をする


あなたの予想は       

予想をしたら、実行ボタンを押してプログラムの動作を確かめましょう。

 


5-6 モジュール (6) ―プログラムの構造―

 

もう一度コードエディタを見てみましょう。


このプログラムは、

 

l         Hantei

l         Keisan

l         Button3Click

 

という3つの部分からできています。

このような、プログラムの中の小さな独立部分を、「モジュール」といいます。

 

C++言語ではこれを「関数」と呼びます。

次に、ヘッダーファイルを見てみましょう。

ここでは、プログラムの中にどのような「関数」があるか、その一覧(リスト)を記述しています。この部分を関数の宣言と呼びます。もう少し詳しく言うと、上の{ }で囲まれた部分には、フォーム上に貼り付けられたコンポーネントや、プログラム中で定義した関数のリストがまとめられています。言わば、ここで作成したフォームに備わっている”性質”の一覧がまとめられている訳です。文法的には、これを「フォームクラスの宣言」と言いますが、ここではこれ以上踏み込みません。

ともかく、C++Builderでは、これらプログラムで使用する関数やコンポーネントのリストを一括して、「***.h」というファイルにまとめます。このファイルがこのプログラムで作成した「ヘッダー(header)」の正体です。他にもプログラムで用いられるC++の命令群を集めたヘッダーなどがあります(3-14節コラム参照)。一方、関数(の本体)の定義は、「***.cpp」ファイルに記述します。一見すると、わざわざ分割してかえって手間がかかるように思えるかもしれませんが、大きなプログラムになると、使用する関数のリストをひとまとめにしておいた方が、プログラムの管理がしやすいのです。

 

コラム  Senderとは?

 
Button3Click関数Keisan(Sender)が実行されると、Keisan関数に飛びます。

 

void__fastcall TForm1::Button3Click(TObject *Sender)

{

  Keisan(Sender);

  Hantei(Sender);

}

void__fastcall TForm1::Keisan(TObject *Sender)

Keisan関数の処理

 
{

  

  

}

 

 このとき、(Sender)と書いてあることによって、どのコンポーネントでこの命令が実行されたかを覚えておくことができるのです。この例題の場合は、Button3がクリックされたときにKeisan(Sender)が実行されるので、C++Builderの内部ではKeisan関数で処理をしている最中にも「Button3から飛んできた」という情報を保存しています。

例えば、Button1をクリックしてもButton2をクリックしてもButton3をクリックしてもKeisan関数に飛ぶとします。そして、スピンエディットのValueプロパティの値を、

l         Button1 がクリックされたときは10倍

l         Button2がクリックされたときは20倍

l         Button3がクリックされたときは30倍

にするとしましょう。このようなとき、どのボタンがクリックされたかという情報を保存しておくことによって、処理の記述が容易になるという利点があるのです。

このプログラムでの、3つのモジュールの関係は、次の図のようになっています


このように、メインプログラムはシンプルに、細かな処理の部分はサブプログラムにまかせるように書くのが、見やすいプログラムといえます。

5-7 関数(1) ―戻り値のない「関数」を作ろう―


これまで何度も目にしてきた、「関数」を定義する

void__fastcall TForm1::Button1Click(TObject *Sender)

{

  

}

という部分は、C++Builderが自動的に作ってくれました。少し、この書式をみてみましょう。C++Builderでは、関数を定義する際の書き方は次のようになっています。

テキスト ボックス: 戻り値の型  __fastcall  関数名(引数リスト)

 

 

これを上の例に当てはめると、対応は次のようになっています。

 

戻り値の型

関数名

引数

void

Button1Click

Sender

 

少し補足説明しておきましょう。

@       戻り値については次節【基礎課題5-8-1】で説明します。

A       __fastcallは、フォームに備わった関数を宣言する際に、用いられる修飾子です。現段階では、必ずつけるものだと捉えておいてください。

B       関数名の前に、「TForm1::」がついていますが、これは、「Form1に所属している」という意味です。「TForm1::Button1Click」は、Form1上に定義されたButton1Click関数という風に読みます。とりあえず、今は必ず「フォーム名::」が先頭につくと考えておいて良いでしょう。

C       引数とは、この関数が呼びされた時、呼び出し元のプログラムから(呼び出された)関数の定義プログラムへ受け渡す変数のことです。これについても、次節【基礎課題5-8-1】でもう少し説明します。

 

さて、上の関数定義部分は、自分で書くこともできます。その練習をしてみましょう。




【基礎課題 5-7-1

 

下のようなフォームを持つプログラムを作って下さい。

主なコンポーネントのNameプロパティは、次のようにして下さい。

コンポーネント

Name

ボタン「計算と判定」

ButtonMain

 

 

 

 

「パソコン本体の値段」と「ディスプレイの値段」を入力してから「計算と判定」ボタンを押すと、

1.       合計金額を表示し、

2.       合計金額が300000以下なら「買える。」そうでなければ「買えない。」と表示する

プログラムを作ります。

まず、
ButtonMain押したときの処理(イベントハンドラ)を、以下のように書いて下さい。

 

void__fastcall TForm1::ButtonMainClick(TObject *Sender)

{

実際に入力するのはこの2行だけです

 
    Keisan();

    Hantei();

}

 

 

ここに、関数「Keisan」や「Hantei」にとって、Senderという引数は必要ないので、( )内は空白にしています。


次に、上に書いた「Keisan」と「Hantei」関数を、自分で次のように書きます。場所は、「ButtonMainClick」の上でも下でも、どちらでも結構です。

 


void__fastcall TForm1::Keisan()

{

合計金額の計算・表示命令を書く

 
   

   

}

 

void__fastcall TForm1::Hantei()

void__fastcallから始まって最後の}まで、すべて自分で書く。

 
{

合計金額が30万年以下ならば

「買える。」と表示し、

そうでなければ

「買えない」と表示させる

 

命令を書く

 
   

 

 

 

 

 

 

 

   

}

 

 

最後に、「Keisan」と「Hantei」という関数を自分で作ったことをC++Builderに知らせるために、関数の宣言を行います。ヘッダーファイルを開いて、下の、枠で囲った2行を追加して下さい。

 

作成したらプログラムを実行して動作を確認してください。


5-8 関数 (2) ―戻り値のある「関数」―

 

これまでみてきた様に、一般にC++言語のプログラムは複数の関数からなります。そして、メインモジュールにあたる「関数」はサブモジュールである「関数」に実行命令を出し、サブモジュールの方は決められた仕事をこなす、という処理の流れになっていました。

 

void__fastcall TForm1::Button3Click(TObject *Sender)

テキスト ボックス: void __fastcall TForm1::Keisan()
{
   Keisan関数の処理
}
{

サブモジュールへ移動

 
  Keisan();

 

 

 

終了後、戻る

 
 

 

 


しかし、プログラミングの中では、

1.       メインモジュールがいくつかの値(引数)を渡し、

2.       サブモジュールがそれをもとに値(答)を計算して、メインモジュールに(戻り値として)返す

という場面が必要になる場合があります。

戻り値

 

引数

 



以下では、このような場合について考えて行きます。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

【基礎課題 5-8-1】


3つの
x,y,z値を渡すと平均値を計算して送り返すサブモジュール(関数)を作成・利用することで、以下のプログラムを完成させましょう。

 

まず、下のようなフォームのプログラムを作って下さい。

 

 

 

 

 

 

 

 

 

主なコンポーネントのNameプロパティは、次のようにして下さい。

コンポーネント

Name

上のスピンエディット

CSpinEditX

中のスピンエディット

CSpinEditY

下のスピンエディット

CSpinEditZ

ボタン

ButtonMain

エディット

EditHeikin



ButtonMainをクリックしたときの処理(イベントハンドラ)は、次のように書いて下さい。

 

void__fastcall TForm1::ButtonMainClick(TObject *Sender)

{

   int x,y,z;

   double a;

   x = CSpinEditX->Value;

   y = CSpinEditY->Value;

   z = CSpinEditZ->Value;

   a = Average(x,y,z);

   EditHeikin->Text = FloatToStr(a)

}

 

Average関数を作ります。下のように書いて下さい。

 


double__fastcall TForm1::Average(int x, int y, int z)

{

   return (x+y+z)/3.0;

}

 

解説

·         Averageは、この関数の名前です。

·         x,y,zは、メインモジュールからサブモジュールに渡される値、つまり引数です。

·         引数がない関数の場合は、前節のように、keisan()などのように、( )内を空白にします。

·         intは、x,y,zint型(整数型)の変数であることを表しています。

·         doubleは、Averageの「戻り値」、要するにAverageの値がdouble型(実数型)であることを表しています。

·         return 式」の形で、「式」の計算結果(値)がAverageの「戻り値」として与えられます。上の例では、(x,y,x)の平均値が戻り値として定義されます。

·         (x+y+z)/3.0」と、分母を「3.0」としている理由については、【基礎課題3-9-1】のコラムを参照してください。

·         前節までのように、戻り値のない関数の場合、戻り値の型としては「void」と書きます。voidは「空っぽ」という意味です。

 

そして、Average関数を作ったことをヘッダーファイルに宣言するのを忘れないで下さい。

下のように、Average関数があることを宣言する必要があります

 


        void __fastcall ButtonMainClick(TObject *Sender);

        double __fastcall Average(int x, int y, int z);

private:   // ユーザー宣言


処理の流れ(イメージ)

 

 

 

 

 

 

 

 


に保存

 

double  Average

 


 

 

 

それでは、実行してみましょう。

 

 

 


5-9 関数 (3) ―絶対値関数を作る―

 

数の絶対値を求める関数を作ります。

【基礎課題 5-9-1

下のようなフォームを持つプログラムを作って下さい。
主なコンポーネントのNameプロパティは、次のようにして下さい。

コンポーネント

Name

左のスピンエディット

CSpinEditFrom

右のスピンエディット

CSpinEditTo

ボタン「絶対値を求める」

ButtonMain

 

 

 

まず、ButtonMainをクリックしたときの処理を、次のように書いてください。

 


void__fastcall TForm1::ButtonMainClick(TObject *Sender)

{

   int a,b;

   a = CSpinEditFrom->Value;  //「もとの数」をaに代入

   b = Zettaichi(a);           //aの絶対値をbに代入

   CSpinEditTo->Value = b;   //bを「絶対値」に代入

}



に、Zettaichi関数をつくります。

その前に、「絶対値」とはなんだったか、復習しておきましょう。

ある数の絶対値とは、その数を数直線上にとった場合の、原点からの距離のことを指します。

−3の絶対値は、            Zettaichi(-3) = 3

5の絶対値は、                 Zettaichi(5)= 5


0の絶対値は、      


aの絶対値は、

   aが正の数のとき、      

 

   aが負の数のとき、      

 

下の下線部を埋めて、関数Zettaichiを完成させてください。

 


int__fastcall TForm1::Zettaichi(int a)

{

   if (               ) {

       return         ;

   }

   else {

       return         ;

   }

}

 

最後に、関数Zettaichiを作ったことを、ヘッダーファイル内で宣言してください。

//---------------------------------------------------------

class TForm1 : public TForm

{

__published:      // IDE 管理のコンポーネント

        TLabel *Label1;

        TLabel *Label2;

        TCSpinEdit *CSpinEditFrom;

        TCSpinEdit *CSpinEditTo;

        TButton *ButtonMain;

        void __fastcall ButtonMainClick(TObject *Sender);

 

        int __fastcall Zettaichi(int a);

 

private:   // ユーザー宣言

public:     // ユーザー宣言

        __fastcall TForm1(TComponent* Owner);

};

//---------------------------------------------------------

 

 

動作を確認してみましょう。

 

 


5-10 関数 (4) ―関数を使う―

 

【基礎課題 5-10-1

前ページで作った絶対値を求めるプログラムを改変します。まず、新しい名前でプログラムを保存し直してください。


まず、ヘッダーファイル内の関数Zettaichiの宣言部分を削除して下さい。

 


        void __fastcall ButtonMainClick(TObject *Sender);

削除

 
        int __fastcall Zettaichi(int a);

private// ユーザー宣言

 

 

さらに、関数Zettaichiの定義部分を削除してください。

 


//----------------------------------------------------------

void__fastcall TForm1::ButtonMainClick(TObject *Sender)

{

   int a,b;

   a = CSpinEditFrom->Value; //「もとの数」をaに代入

   b = Zettaichi(a);        //aの絶対値をbに代入

   CSpinEditTo->Value = b;   //bを「絶対値」に代入

}

//----------------------------------------------------------

 


int__fastcall TForm1::Zettaichi(int a)

{

   if (a >= 0) {

削除

 
       return a ;

   }

   else {

       return -a ;

   }

}

//----------------------------------------------------------


最後
に、「Zettaichi」を「abs」に変えてください。

 


void__fastcall TForm1::ButtonMainClick(TObject *Sender)

absに変える

 
{

   int a,b;

   a = CSpinEditFrom->Value; //「もとの数」をaに代入

   b = Zettaichi(a);        //aの絶対値をbに代入

   CSpinEditTo->Value = b;   //bを「絶対値」に代入

}


すべて保存してからプログラムを実行して、動作を確かめてください。

 

・・・ 先ほどと同様うまく動作するはずです。

 

 

Zettaichi」は、数の絶対値を返す関数でした。

abs」も、数の絶対値を返す関数として機能しています。

 

でも少し腑に落ちませんね。

 

Zettaichi」は、関数の定義部分

 

int__fastcall TForm1::Zettaichi(int a)

{

     ・・・

    ・・・

}

 

が必要だったのに、abs に関しては、われわれは何もしていません。

absは、どうして関数の定義部分がいらないのでしょうか?

実は、abs関数の定義部分はC++Builderの“内部”にあるのです。C++言語にはabs関数の他にも様々な関数を定義しています。これらは「組み込み関数」と呼ばれます。われわれは、それらの関数を、定義することなく使うことができるのです。

定義せずに使える関数の例

関数名

abs()(絶対値関数)

abs(-3)=3

sqrt()

sqrt(9)=3

sin()(サイン関数)

sin(0)=0

cos()(コサイン関数)

cos(0)=1

log()(対数関数)

log(2.71828)=0.999999327347282

exp()(指数関数)

exp(1)=2.71828182845905

 

     上の表で、abs()以外の関数を利用する場合は、「math.h」という(数学関数が収められた)ヘッダーファイルを取り込む必要があります。つまり、プログラムの先頭部に、

 

#include  <math.h>

 

を記述しておく必要があります。


5-11 関数 (5) ―random関数―

Delphiが定義している関数でよく使うものに、random関数があります。random関数は、ランダムな数(乱数)を返す関数です。

【練習問題】

下のようなフォームを持つプログラムを作って下さい。

コンポーネントのNameプロパティは、次のようにして下さい。

コンポーネント

Name

スピンエディット

CSpinEditNumber

ボタン「乱数発生」

Button


ボタンをクリックしたときの命令を、次のように書いてください。

void__fastcall TForm1::ButtonClick(TObject *Sender)

{

   randomize;

   CSpinEditNumber->Value = random(10);       

}

 

 

解説

 

それでは、実行して動作を確かめてみてください。

【基礎課題 5-11-1】

右のようなフォームを持つプログラムを作って下さい。

 

 

ボタンを押すと3つのスピンエディットに0から99までの乱数を発生させるようにしてください。

 

 

 

【応用課題 5-11-A

右のようなフォームを持つプログラムを作って下さい。

 

 

ボタンを押すと3つのスピンエディットに0から2までの乱数を発生させるようにしてください。そして、3つの数がそろったら「大当たり!」と表示して下さい。

 

 

3つの数がそろっていないときは「はずれ!」と表示して下さい。

 

 

 

 

 

 

 

【応用課題 5-11-B

下のようなフォームをもつ、パネルの色が赤/青/黄にランダムに変わるカラースロットマシンをつくります。

 

色の変わるパネルは、「パネルコンポーネント」を使います。コンポーネントパレットのStandardタブにあるパネルを、フォームに3つ貼ります。

 

パネルの色を変えるには、Colorプロパティの値を変えます。図の枠で囲った部分をダブルクリックするか、下向きの三角形をクリックして、左のパネルを赤に、中央のパネルを青に、右のパネルを黄色に変えてください。

 

パネルの色をランダムに変えるプログラムを書きましょう。色々な方法がありますが、例えば、0、1、2の乱数を発生させて、

0のとき赤、1のとき青、2のとき黄

にするようにしましょう。


Panel1の色を赤、青、黄色に変える命令は、それぞれ次のように書きます。

 

最後に、色がそろったときには「大当たり!」、そろわなかったときには「はずれ!」のメッセージを出すのも忘れないでください。


5-12 ローカル変数とグローバル変数

【練習問題】

足し算だけができる簡単な電卓を作ってみましょう。

エディットに適当な数を入力して

+」ボタンを押すと画面には現れない場所 (変数) に値が保存され、エディットは空欄になり、

その後、エディットに別な数を入力して「=」ボタンを押すと

和が求まる、というプログラムです。

 

まずは、フォームにコンポーネントを配置しましょう。

コンポーネント

Name

左のエディット

EditNumber

右上のボタン

ButtonPlus

右下のボタン

ButtonEqual

 

このプログラムでは、整数型変数 PrevNumber を用意して、「+」ボタンが押されたらそこに値を格納するようにします (下のプログラムを参照)。

まず、「+」ボタンのイベントハンドラを書きましょう。

void __fastcall TForm1::ButtonPlusClick(TObject *Sender)

{

   int PrevNumber;  //ここで PrevNumber を用意

   PrevNumber = StrToInt(EditNumber->Text);  //値を格納する

   EditNumber->Text = "";     //エディットを空欄にする  

}

次に、「=」ボタンのイベントハンドラを書きましょう。

void__fastcall TForm1::ButtonEqualClick(TObject *Sender)

{

   EditNumber->Text = IntToStr( PrevNumber

                      + StrToInt(EditNumber->Text) );       

}

 

実行してみましょう。    すると・・・

「未定義のシンボルPrevNumber」というエラーが出ましたね。これは、「PrevNumber という変数 (か何か) を使いたいのだろうけど、そんなものは知らないよ」というエラーです。このエラーをダブルクリックすると、

エラーが発生した行が茶色で、エラーが発生した場所 (C++Builder が解釈できなくなった場所) が水色で示されます。

PrevNumber は宣言したはずなのに、未定義エラーが出たのはなぜでしょうか?

実は、C++言語には、「関数の中で用意された変数は、その関数の中だけで有効である」という決まりがあります。具体的に示すと次のようになります。

ここでPrevNumberは無効

 

PrevNumberはここで破棄される

 

PrevNumberの有効範囲(スコープ)

 

では、どうしたらよいのでしょう? どの「関数」からでも利用できるように、PrevNumber を用意するためには、ヘッダーファイルを開いて下の枠線部を挿入します。

 

また、これで先ほどの変数宣言はいらなくなりました。下線部を削除してください。

void __fastcall TForm1::ButtonPlusClick(TObject *Sender)

{

   int PrevNumber;  //ここで PrevNumber を用意

   PrevNumber = StrToInt(EditNumber->Text);  //値を格納する

   EditNumber->Text = "";     //エディットを空欄にする  

}

 

実行してみましょう。   今度はちゃんと動作するはずです。

このようにどの「関数」からも利用することができる変数を、「グローバル変数 (大域変数) 」と呼びます。一方、「関数」の中で宣言された変数は「ローカル変数 (局所変数)」 と呼ばれます。変数の有効範囲をスコープと言います。

コラム 全てグローバル変数でもいいのでは?

 

「それなら、どんな変数もグローバル変数にするほうが便利なのでは?」と考える人もいるかもしれません。すべての変数をグローバル変数にするとどうなるでしょう?

1.

グローバル変数の「どの関数からも利用できる」という性質は、言い換えれば「どの関数からでもその値を変更 (破壊) することができる」ということです。これはつまり、変数の値がおかしくてプログラムが正しく動かなかったりエラーが発生したりした場合にはすべての関数を疑わなければならないことを意味しています。逆にローカル変数であれば、他の関数からは手が出せないことが保証されているので、該当する関数だけを調べればよいのです。

2.

すべての変数をグローバル変数にすると、変数の名前をたくさん用意しなければなりません。しかし、ローカル変数はその関数内だけで有効ですから、下の例のように、同じ名前の変数を複数の関数で使うことができます。

変数の有効範囲

 
 


void__fastcall TForm1::ShoriA()

{

   int x;

何らかの処理A

 
  

 

別の変数として扱われる

 
}

 

void__fastcall TForm1::ShoriB()

{

   int x;

何らかの処理B

 
  

変数の有効範囲

 
 


}

 

3. プログラミングでは、複数の関数で共有する必要のない限りは「ローカル変数」を使うのが鉄則とされています。

 


5-13 メソッド

【基礎課題 1-7-5】で調べたように、各コンポーネントには、多くのプロパティがあります。例えばエディットなら、 Text プロパティを筆頭に、Top, Visibleなど様々なプロパティがあります。

絶対値を求める abs 関数と同様に、これらのプロパティは C++Builder に最初から備わっているものです*)。「プロパティはコンポーネントに最初から備わっている変数である」と言い換えることもできます。

      ) 厳密に考えると、C++Builder のもととなった C++ 言語の規格が定めているものと、C++Builder の開発者が C++Builder の利用者のために作ってくれたもの (ライブラリと呼ばれます) は別物ですが、ここではその違いを考えません。

そして実は、コンポーネントには変数 (プロパティ) だけでなく関数も最初からいくつか備わっているのです。このような関数は,メソッドと呼ばれます。ここでは、エディットに備わっている Clear メソッドを使って、【基礎課題 4-3-1】で作った検索プログラムを改良してみましょう。

 

【練習問題】

このプログラムは、キーワードを入力しないで「検索」ボタンを押すと「検索用キーワードを入力してください。」という警告が出るというものでした。しかし、一度警告が表示されると、その後キーワードを入力して「検索」ボタンを押しても警告は消えません。そこで、一度警告が出ても、その後ちゃんとキーワードを入力すると警告が消えるように、プログラムを改良しましょう。まずは、今までの知識の範囲で改良します。プログラムを次のように変えてください。(コンポーネントの名前があなたのものと違う場合は適宜読み替えてください。)

 

void __fastcall TForm1::ButtonSearchClick(TObject *Sender)

{

   if(EditKeyWord->Text == "") {

       EditMessage->Text ="検索用キーワードを入力してください。";

   }

   else {

       EditMessage->Text ="";

   }

}

 

正しく動く (警告が1度出た後でもキーワードを入れると警告が消える) ことを確かめたら、プログラムを次のように変更してください。


void __fastcall TForm1::ButtonSearchClick(TObject *Sender)

{

   if(EditKeyWord->Text == "") {

       EditMessage->Text ="検索用キーワードを入力してください。";

   }

   else {

       EditMessage->Text->Clear();

   }

}

先ほどのプログラムと同じように動くことを確かめましょう。

メソッドは、「オブジェクト名->メソッド()」という形で呼び出します。この例

EditMessage->Clear()

は、EditMessage の Clear メソッドを呼び出しています。

 

コラム-メソッド、オブジェクト、オブジェクト指向プログラミングについて

これまで、フォームやEditなどのコンポーネントには、プロパティがあることを学習して来ました。プロパティは、色や高さや幅等々、そのコンポーネントの「性質」を指定するためのものでした。実は、これらコンポーネントには、プロパティという“静的性質”に加えて「メソッド」と呼ばれる“動的操作”が定義されています。上の例でいうと、Clearはエディットに対して定義されているメソッドであるという訳です。

ところで、メソッドとプロパティを有するモノを“オブジェクト”と呼びます。そしてオブジェクトを組み合わせてプログラムを作成するという考え方を“オブジェクト指向プログラミング”と呼びます。オブジェクト指向プログラミング言語であるC++Builderではプロパティティやメソッドを

オブジェクト名->プロパティ   オブジェクト名->メソッド()

という形式で表します。予め、このようにプロパティやメソッドが定義されていればプログラムの開発効率が上がる事は皆も容易に理解できるでしょう。

さて、ここまで説明すると皆は、コンポーネントがオブジェクトであったことに気づいたと思います。きわめて簡略化した説明ですが、とりあえず、“オブジェクト指向プログラミング”という言葉の意味をこのように大まかに捉えておいてください。


エディットに予め備わっているメソッドは、Clear 以外にも何十個もありますが、その全てを紹介すると紙面も時間もかかるので、この教科書では今後も代表的なものしか紹介しません。そこで、「他にはどういうメソッドがあるのだろう?」と興味を持ったあなたのために、メソッドの調べ方を説明しておきましょう。

コンポーネントパレットの中から、調べたいものをクリックし、「F1」を押します。(下の画面はエディットについて調べる例です。)

すると、そのコンポーネントに関するヘルプが表示されるので、「メソッド」をクリックします。

すると、エディットのメソッド一覧が表示されるので、目的のメソッドをクリックします。

 

 

 

 

 

こうして、目的のメソッドの説明が表示されます。説明は難しい内容であることが多いですが、この教科書を読み進んでいくとある程度分かるようになります。

メソッドだけでなくプロパティについても同様の方法で調べることができます。