今回からは、ちょっと気分を変えて新しいクラスを作っていきます。そして、新しい概念「継承」についての話をしていこうと思います。
では、今回の要点です。
では、いってみましょう。
さて、前回までの 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
この講座の著作権はロベールが保有しています