今回からは、ちょっと気分を変えて新しいクラスを作っていきます。そして、新しい概念「継承」についての話をしていこうと思います。
では、今回の要点です。
では、いってみましょう。
さて、前回までの CIntArray は一旦置いておいて、今度はファイルを操作するクラスを作ろうと思います。
ファイルの操作クラスはとても CIntArray と似ているところがあります。ファイルを開くのに失敗すると、ヌルポインタを返してくるあたりがそうです。このあたりの実装は CIntArray ととてもよく似た感じになりますね。
ということで、CFile クラスを作ってみましょう。モードはバイナリモードで固定したいと思います。ファイル操作については第1部第51章から第55章までを参考にして下さい。
| プログラム1 |
|---|
// MainDefs.h #ifndef __MAINDEFS_H__INCLUDED__ #define __MAINDEFS_H__INCLUDED__ #define numof(array) (sizeof (array) / sizeof *(array)) #endif |
| プログラム2 |
// File.h
#ifndef __FILE_H__INCLUDED__
#define __FILE_H__INCLUDED__
#include <stdio.h>
class CFile
{
// メンバ変数
private:
FILE* m_pfile; // ファイル
bool m_bCopy; // コピーコンストラクタで作られたかどうか
// コンストラクタ・デストラクタ
public:
CFile(); // コンストラクタ
CFile(const CFile& rother); // コピーコンストラクタ
~CFile(); // デストラクタ
// ファイルの開閉
public:
bool Open(const char* pszFile, const char* pszFlags);
// ファイルを開く
void Close(); // ファイルを閉じる
private:
bool ModifyFlags(const char* pszSource, char* pszDest, int nSize);
// フラグの調整
// ファイルの操作
public:
size_t Read(void* pData, size_t nSize); // ファイルから読み出す
size_t Write(const void* pData, size_t nSize); // ファイルに書き込む
// 評価
public:
bool IsValid() const; // m_pfile の値が有効かどうか
bool Eof(); // ファイルの終端に達したかどうか
};
// m_pfile の値が有効かどうか
inline bool CFile::IsValid() const
{
return (m_pfile != NULL);
}
#endif |
| プログラム3 |
// File.cpp
#include <stdio.h>
#include <string.h>
#include "MainDefs.h"
#include "File.h"
// コンストラクタ
CFile::CFile()
{
m_pfile = NULL;
m_bCopy = false;
}
// コピーコンストラクタ
CFile::CFile(const CFile& rother)
{
m_pfile = rother.m_pfile;
m_bCopy = true;
}
// デストラクタ
CFile::~CFile()
{
if(m_bCopy == false)
Close();
}
// ファイルを開く
bool CFile::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);
}
// ファイルを閉じる
void CFile::Close()
{
if(IsValid() == true)
{
fclose(m_pfile);
m_pfile = 0;
}
}
// フラグの調整
bool CFile::ModifyFlags(const char* pszSource, char* pszDest, int nSize)
{
bool bBinary; // 'b' の指定があるかどうか
// strchr は、指定した文字が初めに出てくる位置を返す関数です
// ただ単に文字が含まれているかどうかを確認するのにも使えます
bBinary = (strchr(pszSource, 'b') != NULL);
// フラグが多すぎるときは false を返す
if((int)strlen(pszSource) > nSize - 1 - !bBinary)
return false;
// 強制的にバイナリモードで開きます
// strcpy は文字列をコピーする関数、strcat は文字列を追加する関数です
strcpy(pszDest, pszSource);
if(bBinary == false)
strcat(pszDest, "b");
return true;
}
// ファイルから読み出す
size_t CFile::Read(void* pData, size_t nSize)
{
if(IsValid() == false)
return 0;
return fread(pData, 1, nSize, m_pfile);
}
// ファイルに書き込む
size_t CFile::Write(const void* pData, size_t nSize)
{
if(IsValid() == false)
return 0;
return fwrite(pData, 1, nSize, m_pfile);
}
// ファイルの終端に達したかどうか
bool CFile::Eof()
{
if(IsValid() == false)
return true;
return (feof(m_pfile) != 0);
} |
文字列操作関数については第1部第24章を、void* については第3部第4章を参考にして下さい
かなり長いのですが、やってることは大したことはありません。コンストラクタ、デストラクタは単純ですし、読み出し、書き込みもほとんどそのまま関数を呼ぶだけです。
こうして、バイナリモードでファイルを扱うクラスができました。
さて、次はテキストモードでファイルを扱うことを考えたいと思います。
テキストモードでは、テキストを扱うのに特有な関数を用意しておくと便利です。しかし、これをバイナリモード時には使う必要はありません。ということで、CFile クラスは CFile クラスで置いておいて、別のクラス CTextFile として作りたいと思います。
しかし、ファイルを開く部分、読み書きする部分など、CTextFile クラスは CFile クラスと似たようになるはずです。全く別のクラスとして作るのも面倒ですね。CFile を再利用してやることはできないのでしょうか?
そういうときに使うのが継承です。継承は、あるクラスを元に新しいクラスを作ることです。そして、継承元のクラスを基底クラス、継承してできた新しいクラスのことを、元のクラスの派生クラスと呼びます。
派生クラスは基底クラスのメンバを全て持っています。基底クラスのメンバ関数を呼んだり、基底クラスのメンバ変数を使ったりできるわけです。
では、実際にちょっと継承してみましょう。
// TextFile.h
#ifndef __TEXTFILE_H__INCLUDED__
#define __TEXTFILE_H__INCLUDED__
#include <string.h>
#include "File.h"
class CTextFile : public CFile
{
public:
int WriteString(const char* pszString); // 文字列を書き込む
};
// 文字列を書き込む
inline int CTextFile::WriteString(const char* pszString)
{
return Write(pszString, strlen(pszString));
}
#endif |
class CTextFile に続いて、コロンを挟んで public CFile と書いてあります。これが継承の仕方です。
public と書いてあるのは、派生元の public メンバを派生先でも public にするということです。ここを private にすると、CTextFile のオブジェクトでは Open 関数などが使えなくなってしまいます。
で、新しくメンバ関数 WriteString を作っています。これは文字列を書き込む関数で、実装は上にあるとおりです。ここでは基底クラスのメンバ関数 Write を呼んでいます。問題なく使えますね。
ソースが長くなったので、今回はこれで終わろうと思います。内容は少ないんですけどね...。
それでは、今回の要点です。
では、次回まで。
Last update was done on 2000.8.20
この講座の著作権はロベールが保有しています