第13章 関数のすげ替え

 今回は、CTextFile で Open したときはテキストモードで開かれるようにしたいと思います。果たして、その方法とは?


 では、今回の要点です。


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


 前回の ReadLine 関数は、実はテキストモードで開かれていることを前提としたコードになっていました。よく見ると、改行コードが '\n' 1文字であるという想定されていますね。これでは環境依存になってしまいます。

 だから、というわけでもありませんが、さっさとテキストモードで開くように変えてしまいたいものです。ということで、今回はそれをやってみたいと思います。

 とはいえ、どうすればいいのでしょうか? 新しく OpenText 関数でも作ったらいいのでしょうか? しかし、ファイルを開く関数は Open で統一したいものです。

 ということで、とりあえず Open を作ってみましょう。オーバーロードと違い、今度は引数の型が同じになってしまいますが大丈夫なのでしょうか?

プログラム1
// 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
{
    // ファイルを開く
public:
    bool Open(const char* pszFile, const char* pszFlags);
                   // ファイルを開く

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

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

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

#endif
プログラム2
// TextFile.cpp
#include <stdio.h>
#include "MainDefs.h"
#include "TextFile.h"

// ファイルを開く
bool CTextFile::Open(const char* pszFile, const char* pszFlags)
{
    Close();

    char bufFlags[8];
    if(ModifyFlags(pszFlags, bufFlags, numof(bufFlags)) == false)
        return false;

    m_pfile = fopen(pszFile, bufFlags);
    return (m_pfile != NULL);
}

// フラグの調整
bool CTextFile::ModifyFlags(const char* pszSource, char* pszDest, int nSize)
{
    bool bBinary;  // 'b' の指定があるかどうか

    bBinary = (strchr(pszSource, 'b') != NULL);

    // フラグが多すぎるときは false を返す
    if((int)strlen(pszSource) - bBinary > nSize - 1)
        return false;

    // 強制的にテキストモードで開きます
    // 'b' 以外の文字だけコピーします
    for(; *pszSource; pszSource++)
    {
        if(*pszSource != 'b')
        {
            *pszDest = *pszSource;
            pszDest++;
        }
    }
    return true;
}

// 他の実装は省略

 どうやら、エラーは出なかったようです。

 では、実行してみましょう。どちらで開かれたか分かるように、関数にちょっと細工をしておきました。

プログラム2
// TextFile.cpp
#include <iostream.h>
#include <stdio.h>
#include "MainDefs.h"
#include "TextFile.h"

// ファイルを開く
bool CTextFile::Open(const char* pszFile, const char* pszFlags)
{
    cout << "CTextFile::Open" << endl;
    // 後は同じ
}

// フラグの調整
bool CTextFile::ModifyFlags(const char* pszSource, char* pszDest, int nSize)
{
    cout << "CTextFile::ModifyFlags" << endl;
    // 後は同じ
}

// 他の実装は省略
プログラム3
// File.cpp
#include <iostream.h>
#include <stdio.h>
#include <string.h>
#include "MainDefs.h"
#include "File.h"

// ファイルを開く
bool CFile::Open(const char* pszFile, const char* pszFlags)
{
    cout << "CFile::Open" << endl;
    // 後は同じ
}

// フラグの調整
bool CFile::ModifyFlags(const char* pszSource, char* pszDest, int nSize)
{
    cout << "CFile::ModifyFlags" << endl;
    // 後は同じ
}

// 他の実装は省略
プログラム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
CTextFile::Open
CTextFile::ModifyFlags
Viss : No.3

 CFile のオブジェクトからは CFile::Open と CFile::ModifyFlags が、CTextFile のオブジェクトからは CTextFile::Open と CTextFile::ModifyFlags が呼ばれていることが分かります。

 つまり、派生元の関数を派生先で再定義すると、呼び出したオブジェクトの型にあった方の関数が呼ばれるのです。

 このように、派生元の関数を派生先で再定義することオーバーライドと呼びます。これで当初の目的は達せられました。


 早いですが、これで終わりです。1章につき1つずつ、ゆっくりとやっていきましょう。

 では、今回の要点です。


 それでは、次回まで。


第12章 第3のアクセス指定子 | 第14章 仮想関数

Last update was done on 2000.9.7

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