#pragma twice

KAB-studio > プログラミング > #pragma twice > 350 Version 16.23 引数のデフォルト値

#pragma twice 350 Version 16.23 引数のデフォルト値

前のページへ 表紙・目次へ 次のページへ

 Version 16.23
引数のデフォルト値

「今回は引数のデフォルト値について説明します」
『演算子のオーバーロードからうってかわって、って感じだね』
「ううん、実はとても関係があるんです」
『え?』
「まずは実例から。引数のデフォルト値は普通の関数でもメンバ関数でもで
きるから、普通の関数で試してみます」

// Data.h
void UseDefault( int p_i1, int p_i2 = 100 );


// Data.cpp
#include <Windows.h>
#include <stdio.h>

#include "Data.h"

// 引数のデフォルト値を持つ関数。
void UseDefault( int p_i1, int p_i2 )
{
    // 配列の方を出力します。
    char pch[256];
    sprintf( pch, "%d, %d\n", p_i1, p_i2 );
    OutputDebugString( pch );
    // 100, 101
}

「 UseDefault() の第2引数で 100 というデフォルト値を使用しています」
『【 int p_i2 = 100 】がそうね』
「使用例は以下のようになります」

// Main.cpp
#include <Windows.h>
#include <stdio.h>

#include "Data.h"

int WINAPI WinMain
    ( HINSTANCE p_hInstance
    , HINSTANCE p_hPrevInstance
    , LPSTR p_pchCmdLine
    , int p_iCmdShow
    )
{
    // デフォルト値を使用します。
    UseDefault( 100 );
    // 100, 100

    // デフォルト値を使用しません。
    UseDefault( 200, 300 );
    // 200, 300

    return 0;
}

「最初の方は、デフォルト値を使用して呼び出しています」

    // デフォルト値を使用します。
    UseDefault( 100 );
    // 100, 100

「このように、引数を省略するとデフォルト値が使用されます。つまり、 
p_i2 に 100 が渡されて呼び出される、ということです」

    // デフォルト値を使用します。
    UseDefault( 100  /* 第2引数を省略 */ );
                 ↓            ↓
                 ↓            ↓
                 ↓            →→→→→
                 →→→                ↓
                      ↓               ↓
void UseDefault( int p_i1, int p_i2 = 100 );
                     ↓               ↓
                     ↓         ←←←←
                     ↓         ↓
void UseDefault( int p_i1, int p_i2 )
{
// 略

『省略すると、その値が渡されるってわけね』
「もちろん、デフォルト値を使用しないこともできます」

    // デフォルト値を使用しません。
    UseDefault( 200, 300 );
    // 200, 300

『だからデフォルト値、なんだもんね』
「そういうこと」
『……質問!』
「はい火美ちゃん」
『これって宣言の方だけでいいの? 定義の方はいらないの?』
「そこが複雑なところなんです。たとえば、以下のようにデフォルト値の
設定を、定義の方だけしたとします」

// Data.h
void UseDefault( int p_i1, int p_i2 );

// Data.cpp
#include <Windows.h>
#include <stdio.h>

#include "Data.h"

// 引数のデフォルト値を持つ関数。
void UseDefault( int p_i1, int p_i2 = 100 )
{
// 略

『げ、コンパイルエラーになった!』

    // デフォルト値を使用します。
    UseDefault( 100 );
    // コンパイルエラー:
    // error C2660: 'UseDefault' : 
    //     関数が不正な 1 個の実引数をともなって呼び出されました。

『なんでなんで!? 宣言の方に書かないといけないの?』
「宣言の方に書かなきゃいけないわけじゃなくて、コンパイルするときに
デフォルト値の情報がないといけないんです」
『???』
「コンパイラのことを思い出して。まず、コンパイルはソースファイル単位
で行うよね」
『 Version 15.01 ( No.301 ) とかで教わったね』
「コンパイラは、 Main.cpp をコンパイル中に、以下の文にでくわします」

    // デフォルト値を使用します。
    UseDefault( 100 );

「コンパイラは、この UseDefault() 関数の引数と戻り値の情報を取得しよ
うとします。その情報はどこに書かれてる?」
『 Data.h と Data.cpp 』
「でも、コンパイルはソースファイル単位でしょ」
『あ、そっか。 Main.cpp のコンパイルしてるときには Data.cpp は見てな
いんだ。 Main.cpp からは Data.h をインクルードしてるから見えるけど』

// Main.cpp
#include <Windows.h>
#include <stdio.h>

#include "Data.h"

「そう、だから Main.cpp のコンパイル時には Data.h の情報を持つことに
なります。その中で、以下の関数を見つけます」

// Data.h
void UseDefault( int p_i1, int p_i2 );

『デフォルトの引数使っていないバージョンね』
「コンパイラは、呼び出し元の引数が1つだけなのに、宣言の方は引数が2つ
の関数しかないから、どの関数を呼び出せばいいのかわかりません」
『コンパイラは Data.h しか見られないから、定義の方にデフォルト値書い
ても分からない、って話?』
「そういうこと。デフォルト値はコンパイル時に使用されるので、コンパイル
するときに見に行く Data.h の宣言に書く必要があります」

// Data.h
void UseDefault( int p_i1, int p_i2 = 100 );

「このようにすることで、コンパイラは呼び出し部分にデフォルト値を渡す
ようにします」

    // デフォルト値を使用します。
    UseDefault( 100, 100 );
//                    ↑デフォルト値

『呼び出すとこにデフォルト値を渡しちゃう渡すわけね』
「このように、デフォルト値はコンパイル時に処理されるので、宣言に書く
必要があります」
『コンパイラから見えなきゃいけないわけね』
「ただ、定義に書いてもいい場合もあります」
『定義に書いてもいい場合?』
「定義しかない場合とかね

// Main.cpp
#include <Windows.h>
#include <stdio.h>

// 引数のデフォルト値を持つ関数。
void UseDefault( int p_i1, int p_i2 = 100 )
{
    // 配列の方を出力します。
    char pch[256];
    sprintf( pch, "%d, %d\n", p_i1, p_i2 );
    OutputDebugString( pch );
    // 100, 101
}

int WINAPI WinMain
    ( HINSTANCE p_hInstance
    , HINSTANCE p_hPrevInstance
    , LPSTR p_pchCmdLine
    , int p_iCmdShow
    )
{
    // デフォルト値を使用します。
    UseDefault( 100 );
    // 100, 100

    // デフォルト値を使用しません。
    UseDefault( 200, 300 );
    // 200, 300

    return 0;
}

『あー、定義ファイルにしかない場合は仕方ないよね』
「どちらにしろ、コンパイラがデフォルト引数が得られればいい、ってこ
とだから」

/*
    Preview Next Story!
*/
『あれ? オーバーロードと関係してるって話は?』
「引数を省略、ってオーバーロードでもできるでしょ」
『そういえば、ってここで言われても』
「じゃあ1回そのために取りましょう」
『げ』
「というわけで次回」
< Version 16.24 デフォルト値vsオーバーロード >
『につづく!』
「こうしてどんどん伸びていく」
『自分で言うなー! もう7年だよー!?』
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。