継承関係のあるクラスの関数をオーバーライドしたい場合にポリモーフィズム実現のために利用する 仮想関数 だが(実装を持たない場合、純粋仮想関数)、なぜ 仮想関数 を定義したクラスのデストラクタは virtualでなくてはならないのか。
【復習】
仮想関数
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Stream.h | |
// CplusplusPractice | |
// | |
// Created by masai on 2015/05/20. | |
// Copyright (c) 2015年 masai. All rights reserved. | |
// | |
#ifndef __CplusplusPractice__Stream__ | |
#define __CplusplusPractice__Stream__ | |
class Stream{ | |
public: | |
double Get() const; | |
bool Set(); | |
protected: //派生クラスで使用可能 | |
virtual void SetBase() = 0; | |
double m_n; | |
}; | |
#endif /* defined(__CplusplusPractice__Stream__) */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Stream.cpp | |
// CplusplusPractice | |
// | |
// Created by masai on 2015/05/20. | |
// Copyright (c) 2015年 masai. All rights reserved. | |
// | |
#include <iostream> | |
#include "Stream.hpp" | |
using namespace std; | |
double Stream::Get() const{ | |
return m_n; | |
} | |
bool Stream::Set(){ | |
cout << "Stream::Set" << endl; | |
SetBase(); | |
return m_n >= 0; | |
} | |
// 必ず子供で実装するので実装が不要→純粋仮想関数 | |
//void Stream::SetBase(){ | |
// cout << "Stream::SetBase" << endl; | |
// m_n = -1; | |
//} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// ArrayStream.h | |
// CplusplusPractice | |
// | |
// Created by masai on 2015/05/20. | |
// Copyright (c) 2015年 masai. All rights reserved. | |
// | |
#ifndef __CplusplusPractice__ArrayStream__ | |
#define __CplusplusPractice__ArrayStream__ | |
#include "Stream.hpp" | |
class ArrayStream : public Stream{ | |
public: | |
ArrayStream(const double* array); //コンストラクタ | |
protected: | |
virtual void SetBase(); | |
private: | |
const double* m_array; //配列 | |
int m_i; //現在のインデックス | |
}; | |
#endif /* defined(__CplusplusPractice__ArrayStream__) */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// ArrayStream.cpp | |
// CplusplusPractice | |
// | |
// Created by masai on 2015/05/20. | |
// Copyright (c) 2015年 masai. All rights reserved. | |
// | |
#include <iostream> | |
#include "ArrayStream.hpp" | |
using namespace std; | |
ArrayStream::ArrayStream(const double* array){ | |
m_array = array; | |
m_i = 0; | |
} | |
void ArrayStream::SetBase(){ | |
m_n = m_array[m_i]; | |
++m_i; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// InputStream.hpp | |
// CplusplusPractice | |
// | |
// Created by masai on 2015/05/20. | |
// Copyright (c) 2015年 masai. All rights reserved. | |
// | |
#ifndef CplusplusPractice_InputStream_hpp | |
#define CplusplusPractice_InputStream_hpp | |
#include "Stream.hpp" | |
class InputStream : public Stream{ | |
protected: | |
virtual void SetBase(); | |
}; | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// InputStream.cpp | |
// CplusplusPractice | |
// | |
// Created by masai on 2015/05/20. | |
// Copyright (c) 2015年 masai. All rights reserved. | |
// | |
#include <iostream> | |
#include "InputStream.hpp" | |
using namespace std; | |
void InputStream::SetBase(){ | |
cin >> m_n; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// inheritance.cpp | |
// CplusplusPractice | |
// | |
// Created by masai on 2015/05/20. | |
// Copyright (c) 2015年 masai. All rights reserved. | |
// | |
#include <iostream> | |
#include "Stream.hpp" | |
#include "InputStream.hpp" | |
#include "ArrayStream.hpp" | |
using namespace std; | |
bool Average(Stream& stream){ | |
int count; | |
double avr = 0; | |
for(count = 0; stream.Set(); ++count){ | |
avr += stream.Get(); | |
} | |
if(count == 0){ | |
return false; | |
} | |
avr /= count; | |
cout << "average is " << avr << endl; | |
count = 0; | |
return true; | |
} | |
int main(){ | |
// ArrayStream | |
static const double array1[] = {1, 2, 3, 4, 5, 6, -1}; | |
static const double array2[] = {2, 4, 5, 6, 1, -1}; | |
static const double* const array[] = {array1, array2}; | |
// sizeは全体のメモリサイズ / 要素(最初の一つ目)のメモリサイズ | |
static const int size = sizeof array / sizeof *array; | |
for(int i = 0; i < size; ++i){ | |
ArrayStream stream(array[i]); | |
if(! Average(stream)){ | |
//break; | |
} | |
} | |
// InputStream | |
while(true){ | |
InputStream stream; | |
if(! Average(stream)){ | |
break; | |
} | |
} | |
} |
仮想関数テーブル
virtual function table, vtable という隠しメンバ変数を使って実現される。
ある仮想関数を呼び出したとき、実装にはどの関数かを管理するテーブル仮想関数テーブルは実行時、コンストラクタで初期化されてデストラクタで破棄されるので、不要な場合はvirtualにしないほうが仮想関数テーブルの分だけメモリ使用量は節約できるし、効率もあがる。
仮想関数を定義したクラスのデストラクタ
仮想関数の利用シーンは、「子クラスのポインタ」を「親クラスのポインタ」にキャストして使って、仮想関数の実装だけ入れ替えるようにして利用(ポリモーフィズム)がほとんどのはずである。
このとき、親クラスのポインタ(実体は子クラス)に対して delete した際、親クラスのデストラクタがvirtualでない場合、子クラスのデストラクタが呼ばれず、メモリリークが発生する。
また、親クラスが暗黙的に作成するデストラクタはvirutalでは無いので、内容がなかったとしても以下のように明示的に宣言すること。
virtual ~ParentClazz() {}
0 件のコメント:
コメントを投稿