第14章 仮想関数

 前回のプログラムをよく見ると、ちょっと不経済なところがあります。今回はその点を何とかしたいと思います。


 では、今回の要点です。


 では、いってみましょう。


 実は、前回の CTextFile::Open 関数の中身は CFile::Open 関数と全く同じでした。これはさすがに不経済ですね。

 では、Open は CFile::Open を使い、ModifyFlags だけを呼び分けるようにすればいいでしょう。

 ということでやってみました。

プログラム1実行結果
// TestFile.cpp
#include <iostream.h>
#include "File.h"
#include "TextFile.h"

// CTextFile::Open を消去して下さい

void Viss(const int num)
{
    cout << "Viss : No." << num << endl;
}

int main()
{
    CFile     bin;
    CTextFile txt;

    Viss(1);
    bin.Open("Test.txt", "r");
    Viss(2);
    txt.Open("Test.txt", "r");
    Viss(3);

    return 0;
}
Viss : No.1
CFile::Open
CFile::ModifyFlags
Viss : No.2
CFile::Open
CFile::ModifyFlags
Viss : No.3

 ...あれ? 両方とも CFile::ModifyFlags を呼んでいますね。

 これは、こういうことなのです。ModifyFlags は CFile の Open から呼ばれたので、CFile の ModifyFlags が呼ばれてしまったのです。

 よく考えたら、確かにそうでないと困ることもあるでしょう。いつもそうなると、うっかり後で動作を変えてしまわないか、ビクビクしながら継承しなければいけなくなります。

 しかし、逆にそうだと困ることもあります。それが今ですね。何とか、後で動作を変えるようにできればいいと思いませんか?


 そういうときに使うのが仮想関数です。仮想関数にすると、派生元の関数からでも適切なオーバーライド関数を呼びだしてくれるようになります。

 仮想関数にする方法は簡単です。関数プロトタイプの前に virtual と書くだけでいいのです。一応、基底クラスに書いておくだけで構わないのですが、派生クラスにも書いておくと、その関数が仮想関数だということがよく分かっていいでしょう。

 で、結局次のようになります。

プログラム2
// File.h
#ifndef __FILE_H__INCLUDED__
#define __FILE_H__INCLUDED__

#include <stdio.h>

class CFile
{
private:
    virtual bool ModifyFlags(const char* pszSource, char* pszDest, int nSize);
                   // フラグの調整

    // 他のメンバは省略
};

// インライン関数の実装は省略

#endif
プログラム3
// TextFile.h
#ifndef __TEXTFILE_H__INCLUDED__
#define __TEXTFILE_H__INCLUDED__

#include <stdio.h>
#include <string.h>
#include "File.h"

const int TF_OVERFLOW = EOF - 1;  // オーバーフロー

class CTextFile : public CFile
{
private:
    virtual bool ModifyFlags(const char* pszSource, char* pszDest, int nSize);
                   // フラグの調整

    // 他のメンバは省略
};

// インライン関数の実装は省略

#endif
プログラム4実行結果
// TestFile.cpp
#include <iostream.h>
#include "File.h"
#include "TextFile.h"

void Viss(const int num)
{
    cout << "Viss : No." << num << endl;
}

int main()
{
    CFile     bin;
    CTextFile txt;

    Viss(1);
    bin.Open("Test.txt", "r");
    Viss(2);
    txt.Open("Test.txt", "r");
    Viss(3);

    return 0;
}
Viss : No.1
CFile::Open
CFile::ModifyFlags
Viss : No.2
CFile::Open
CTextFile::ModifyFlags
Viss : No.3

 めでたく、CTextFile の ModifyFlags が呼ばれましたね。

 このように、仮想関数にすると、基底クラスで呼ばれた関数を後からすげ替えることができるのです。


 では、今回の要点です。


 それでは次回まで。


第13章 関数のすげ替え | 第15章 アップキャスト

Last update was done on 2000.8.20

この講座の著作権はロベールが保有しています