【C++Builder Starter チュートリアルシリーズ】 シーズン2 第4回 ‟関数„ [JAPAN]

Posted by on in Blogs

【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第3回 ‟条件とループ„ [JAPAN]

C++Builder Starter Edition シーズン2 第4回 ‟関数„

2017年1月23日より 「Delphi / C++Builder Starter チュートリアルシリーズ」 シーズン2、全9回、3月27日まで、毎週月曜日、Delphiパートが 17時00分~17時20分、 リアルタイム放送スペシャルコンテンツが5分~10分、C++Builderパートは 17時30分~17時50分の時間割でお送りしています。

無料でダウンロード&利用できる開発環境のDelphi / C++Builder Starter エディションを使用して、プログラミング言語のDelphi (Object Pascal ), C++の基礎を学ぶオンラインセッションです。

https://community.embarcadero.com/blogs/entry/2-japan

 

サマリ

アジェンダ

  • 今日のねらい

    • 関数について知る
    • 関数と書き方
  • 実施内容

    • 関数の書き方
    • 引数、戻り値
    • 宣言

スライド資料

http://www.slideshare.net/ssuser8bd3f7/cbuilder-starter-2-cbuilder-4

開発環境のインストール

開発環境のインストールについては、[Delphi / C++Builder Starter チュートリアルシリーズ] 第1回 ‟無料で始めよう アプリ作成„ にて丁寧な説明がありますので、そちらをご視聴の上でインストールを進めてください。

https://community.embarcadero.com/blogs?view=entry&id=9038

実施内容

関数とは?

  • 前提条件(引数)を与えると、それに基づいた結果(戻り値)が決まる処理のこと
  • 例えば「自動販売機」を関数と考えてみると「代金」と「商品ボタン」を押すことが前提条件にあたる
  • 自動販売機で期待される処理結果は「選んだ商品が出る」、「釣銭を返却する」こと

C++における関数とは?

  • 一連の処理を再利用可能とするために名前を付けたもの
  • 関数を利用するには宣言と定義が必要
  • 定義は関数を実際に実装したもので、宣言を伴う
  • 関数宣言部だけを単独で書くこともできる(この目的は後述)

関数の実装例

int myIncFunction( int i ) // 関数名の前の int は、戻り値の型指定
{
  //戻り値は return で返す。
  return i + 1; 
}

int myIncFunction2( int i )
{

} // return xx; が無い場合は return 0; が省略されているものとして扱う

// 戻り値の型を void とすると、戻り値が返されない
void myFunction(UnicodeString message)   
{
  ShowMessage( message );
}

// [C言語向け] 引数をとらない関数は、パラメータ部分に void と書く 
void Hello( void )
{
  ShowMessage( L”Hello world” );
}

// [C++言語向け]引数をとらない関数は、パラメータ部分の void の記述をを省略してもよい
void HelloCpp( )
{
  ShowMessage( L”Hello C++Builder world” );
}

関数の引数と戻り値

  • 関数の引数には関数宣言の型と一致する型のデータを渡す
  • 関数の引数に一致しない型の値が渡された場合は……
    • 型変換が可能な場合はキャストされるため、キャストの結果によっては意図とは異なる値になる
    • 型変換が行えない場合はエラーとなる
  • 関数使用時の引数(パラメータ)には式を使用可能
double DoubleValue(int iNum)
{
  return iNum * 2;
}

void __fastcall TForm1.Button1Click(Tobject *Sender)
{
 int i; 
 i = DoubleValue(8-1);      // OK: 式の結果は整数値なので、これは関数の仕様と合致している
 i = DoubleValue(10.2);     // 値が正しく扱われない: 実数値はキャストで四捨五入されてしまい、”10” が関数に渡される
 i = DoubleValue(L”文字列”); // コンパイルできない: 整数型をとるパラメータに文字列を渡しているので型が一致しない
}

return - 関数の実行途中で関数を抜ける

  • 関数の処理中に return [戻り値]; が出現したら、そこで関数を終了する
  • ループの深い階層からも抜けられる
  • 関数の処理内容によっては、ループを抜ける前の後始末が必要なことも(後述)
void __fastcall TForm1::Button4Click(TObject *Sender)
{
      UnicodeString str = L"Hello C++Builder";

      for (WCHAR c : str ) {
      if ( c == 'B' ) return; // 文字 'B' を見つけたら関数を抜ける
       Memo1->Lines->Add( Format(L"%s", ARRAYOFCONST(( c )) ) );
    }
    Memo1->Lines->Add( L"END" ); // return で抜けた場合はこの処理に到達しない
}

関数の記述順序

  • 関数は、ソースコード内で定義された順番で利用できる
// mySomeFunction() は main() より前に定義されているので関数が仕様どおりに呼ばれていることが検証できる
double mySomeFunction (double i ) 
{
    return i * 3.14; 
}

void main( void )
{
    double myvalue = mySomeFunction( 2 );
    ShowMessage(
        Format( L”%f”, ARRAYOFCONST((myvalue)) )
    ); 
}
// mySomeFunction() が main() より後に定義されているので呼び出し方が分からず、エラーになる
void main( void )
{
    double myvalue = mySomeFunction( 2 );
    ShowMessage(
        Format( L”%f”, ARRAYOFCONST((myvalue)) )
    ); 
}

double mySomeFunction (double i ) 
{
    return i * 3.14; 
}
  • 関数を予め宣言していれば、呼び出す場所と定義の順番によらず関数呼び出しが行える
double mySomeFunction(double i ); // 関数宣言部

double mySomeFunction(double i ) 
{
    return i * 3.14; 
}

void main( void )
{
    double myvalue = mySomeFunction( 2 );
    ShowMessage(
        Format( L”%f”, ARRAYOFCONST((myvalue)) )
    ); 
}
double mySomeFunction(double i ); // 関数宣言部

void main( void )
{
    double myvalue = mySomeFunction( 2 );
    ShowMessage(
        Format( L”%f”, ARRAYOFCONST((myvalue)) )
    ); 
}

double mySomeFunction (double i ) 
{
    return i * 3.14; 
}

宣言と定義の分離でもたらされることは?

  • 関数宣言が事前に行われると、関数定義の場所や順番によらず関数が呼び出せるようになる
  • 関数宣言をソースコードから分離した別ファイル(ヘッダファイル)に記述すれば、別のソースコードからも関数が呼べるようになる

自らの関数を呼び出すことが可能 「再帰呼び出し」

  • 自らを呼び出す関数
  • ループの代わりに使用したり、フォルダ階層の読み取りなどに使用
int __fastcall TForm1::Recursive( int count )
{
    int retval = count - 1;

    if ( retval > 0 ) Recursive( retval );  // 再帰呼び出しは実行条件を決めて行う

    Memo1->Lines->Add( IntToStr( retval ) );
    return retval;

}

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    Recursive( 3 );
}

パラメータのデータ・変数の受け渡しについて

  • 関数でパラメータにデータを渡す方法は「値渡し」と「参照渡し」がある
  • デフォルトでは値渡し
    • 呼び出し先の関数では渡された値を新たにコピーしてから使用する
    • 呼び出された関数が渡された値を変更しても、呼び出し元の変数はその変更の影響を受けない
      • 宣言部で変数名の前に & がついていたら参照渡しになる
      • 参照渡しでは、変数の入れ物(保存場所)の情報を受け渡す
      • 呼び出された関数で変数の値を変更すると、呼び出した側の変数も値が変わる
// 値渡しの例
int x, i = 4;

/* i は 4 のまま変化しない。x の値は 4 x 3 = 12 となる */
x =値渡しの関数(i);

int 値渡しの関数(int value)
{
    int retval = 3 * value;

    value = 0;
    return retval;
}
// 参照渡しの例
int i = 6;

/* x の値は参照渡しで実行した関数により 36 に変わる */
参照渡しの関数( i );

void 参照渡しの関数(int &ref )
{
    ref = ref * 3;
}

関数のオーバーロード

  • 同じ名前でパラメータの型が異なる複数の関数を宣言・定義できる
  • 呼び出しの際の引数の型に応じて実行する関数が自動的に選択される
  • 同名のオーバーロード関数の型はすべて同じであることが必要
void __fastcall TForm1::overload_example( int n )
{
    Memo1->Lines->Add(
    Format( L"overload_example( int ) = %d", ARRAYOFCONST(( n )) )
    );
}

void __fastcall TForm1::overload_example( double n )
{
    Memo1->Lines->Add(
    Format( L"overload_example( double ) = %.16f", ARRAYOFCONST(( static_cast<const long double>(n) )) )
    );
}

overload_example( 1 );        // 引数 int の関数を実行する
overload_example( 3.141592 );    // 引数 double の関数を実行する

__fastcall

  • C++Builderのイベントハンドラに自動的につけられる修飾子
  • C++Builderで関数を作るときにはつけるものと理解しておく
  • 正確な話は…
    • 関数実行時の引数の渡し方の規約
    • その他の修飾子
      • パラメータのスタック経由渡し (C言語標準の cdecl)
      • パラメータのレジスタ経由渡し (fastcall, stdcall)

http://docwiki.embarcadero.com/RADStudio/ja/Fastcall、_fastcall
http://docwiki.embarcadero.com/RADStudio/ja/関数修飾子
http://docwiki.embarcadero.com/RADStudio/ja/言語混在時の呼び出し規約

他、関連する機能など

セミナー動画

チュートリアルセミナー視聴ページにて、シーズン2の放送分を視聴できるようにしています。チュートリアルシリーズに申し込み済みの方はメールにてご案内済みの視聴ページよりご視聴ください。まだ申し込んでいない方は下記アドレスよりお申込みいただくと視聴できます。

http://forms.embarcadero.com/starter-tutorial-webinar

また、シーズン1の放送分は youtube の下記ページよりご視聴いただけます。

https://www.youtube.com/playlist?list=PLoQxxVNY10oEmNSjiPdYPV_E9IL9ipico

シーズン1のまとめ記事もございますので、こちらも併せてお読みください。

https://community.embarcadero.com/blogs/entry/delphi-c-builder-starter-japan

■次回のC++Builderパートは2月20日(月) 17:30頃より、“配列と構造体„をお送りいたします。。

 


About
Gold User, No rank,
Sales Consultant at Embarcadero Technologies, in Japan.

Comments

Check out more tips and tricks in this development video: