今回は継承を使ったクラスを関数に渡してみたいと思います。「何だ、それだけか」と思われるかもしれませんが、それだけじゃないんです、これが。
では、今回の要点です。
では、いってみましょう。
今回は、ファイルを開く部分を別の関数(メンバ関数ではありません)にしたいと思います。ファイル名を入力し、そのファイルを開くという関数です。
この際渡す引数は、やはり CFile もしくは CTextFile のオブジェクトです。ということで、早速やってみたいと思います。
#include <iostream.h>
#include "File.h"
#include "TextFile.h"
bool Open(CFile& rfile, const char* pszFlags)
{
    char buffer[512];
    cout << "ファイル名を指定して下さい > " >> flush;
    cin >> buffer;
    return rfile.Open(buffer, pszFlags);
}
bool Open(CTextFile& rfile, const char* pszFlags)
{
    char buffer[512];
    cout << "ファイル名を指定して下さい > " >> flush;
    cin >> buffer;
    return rfile.Open(buffer, pszFlags);
} | 
型が違うからこうしたのですが...何というか、不経済ですね。
そういえば第11章で、「派生クラスは基底クラスのメンバを全て持っている」と言いました。なら、派生クラスのオブジェクトを基底クラスへの参照に渡しても、動作に問題はなさそうです。基底クラスのメンバは全て持っているわけだから、データが多いことはあっても、足りないことはないはずです。
そして、Open 関数は CFile のものを使っているので、その呼び出しに問題はないはずです。
というわけで、CTextFile への参照をとる関数は消して、CFile への参照をとる関数だけを残しましょう。
| プログラム | 
|---|
// TestFile.cpp
#include <iostream.h>
#include "MainDefs.h"
#include "File.h"
#include "TextFile.h"
bool Open(CFile& rfile, const char* pszFlags)
{
    char buffer[512];
    cout << "ファイル名を指定して下さい > " << flush;
    cin >> buffer;
    return rfile.Open(buffer, pszFlags);
}
void Write(CTextFile& rtxt)
{
    char buffer[512];
    cout << "何を書き込みますか > " << flush;
    cin >> buffer;
    rtxt.WriteString(buffer);
}
void Load(CFile& rbin)
{
    char buffer[512];
    int  nRead;
    nRead = rbin.Read(buffer, numof(buffer));
    buffer[nRead] = 0;
    cout << buffer << endl;
}
int main()
{
    CFile     bin;
    CTextFile txt;
    if(Open(txt, "w") == false)
        return 0;
    Write(txt);
    txt.Close();
    if(Open(bin, "r") == false)
        return 0;
    Load(bin);
    bin.Close();
    return 0;
} | 
| 実行結果例 | 
ファイル名を指定して下さい > Test.txt CFile::Open CTextFile::ModifyFlags 何を書き込みますか > ペペロンチーノ ファイル名を指定して下さい > Test.txt CFile::Open CFile::ModifyFlags ペペロンチーノ  | 
おお、きちんと動きました。CTextFile の ModifyFlags が呼ばれています。
このように、派生クラスのオブジェクトを基底クラスへの参照、ポインタに対して渡すことは可能です。このことをアップキャストと言います。
しかし、ちょっと待って下さい。そういえば仮想関数を使っていましたね。これって何か影響あるんでしょうか?
では、virtual を消してもう一度やってみましょう。
| 実行結果例 | 
|---|
ファイル名を指定して下さい > Test.txt CFile::Open CFile::ModifyFlags 何を書き込みますか > ペスカトーレ ファイル名を指定して下さい > Test.txt CFile::Open CFile::ModifyFlags ペスカトーレ  | 
今度は CFile の ModifyFlags が呼ばれてしまいました。
これは前回と同じ状況ですね。CFile の参照から呼ばれたから CFile の ModifyFlags が呼ばれたのです。そして、それを回避し、オブジェクトの本当の型に対する ModifyFlags を呼ぶために仮想関数を使うわけです。
最後にもう一度仮想関数についてまとめます。
普通は、呼び出すときに使った型に対応する関数が呼ばれます。しかし、仮想関数にしていれば、そのオブジェクトの本当の型に対応する関数が呼ばれるのです。
では、今回の要点です。
それでは、また次回まで。
Last update was done on 2000.8.21
この講座の著作権はロベールが保有しています