virtual……仮想継承ってなあに
ちまたで、virtualとか見かけてついeclipseでコードをかいてみたので書いてみる。
「仮想仮想とでてきて、C++は仮想が大好きですね」*1
とか思いますが仮想継承というのは、多重継承をしない限りいらないので覚えなくて良いです。
どうしても多重継承したい! というときに使うかもしれません。
で、多重継承。
Hoge : Foo, Barと多重継承した場合、FooとBarのインスタンスは別物として扱われます。
要するにFooとBarが同名のメンバ変数やメンバ関数を持っていてもそれは別物です。
なので、
Foo : Base,
Bar : Base,
Hoge : Foo, Bar
という多重継承をした場合にBaseのインスタンスはFoo::Baseと、Bar::Baseとがあって、Hogeはその両方を持ちます。
でも、恐らくこういう場合に設計者はBaseのインスタンスを共通で利用したいと考えている筈です。(多くの場合)
で、これを解決するのが仮想継承です。
class File { protected: unsigned char* _file; int _cursor; public: File() { _file = new unsigned char[100]; _cursor = 0; } virtual ~File() { delete _file; } void reset() { _cursor = 0; } }; class OutputFile : virtual public File { public: unsigned char read() { return _file[_cursor++]; } }; class InputFile : virtual public File { public: void write(unsigned char data) { _file[_cursor++] = data; } }; class SaveDataFile : public OutputFile, public InputFile { }; int main(int argc, char *argv[]) { SaveDataFile* file = new SaveDataFile(); file->write(1); file->write(2); file->write(3); file->write(4); file->write(5); file->reset(); for (int i = 0; i < 5; i++ ) { unsigned char data = file->read(); printf( "[%d]?n", data ); } }
糞の役にもたたないコードですが、こういう感じで使えます。
Fileは何かのファイル(操作)を抽象化したもので、それにInputとOutputをするための継承があり、
その両方をサポートしているSaveDataFileがあるということです。
この継承をvirtualにしない場合、Fileのメンバはすべて個々に継承されるため、
例えば、resetを呼び出そうとすると
「だんなさん、どっちを呼んだらいいかわからねえっすよ」とコンパイラおばさんに怒られる羽目になります。
こんなのあんまりかかないと思うけど。
こういうのを考えたりしないといけないので、C++はめんどいです。
ある意味、危険で自由ですが。
僕もまるでわかりません。
*1:仮想をつけるとオーバーヘッドがあるのであえてつけてない設計です