C++継承におけるダミー構造関数
7610 ワード
次のプログラムに何かエラーがあるか見てみましょう.
このプログラムはVC++6.0の実行後にエラーが発生していません.
上記の手順を次のように変更します.
実行結果:
contructor Father!contructor Son!destructor Father!
派生クラスSonは解析されていないことは明らかであり,すぐにC++継承における虚解析関数の問題を引き出した.
(1)ベースクラスの構造関数が虚関数でない場合,ポインタを削除すると,そのクラスのメモリのみが解放され,派生クラスは存在しない.これでメモリが漏れました.
(2)構造関数が虚関数でない場合は,そのタイプの構造関数コードをポインタタイプで直接呼び出し,ポインタタイプがベースクラスであるため,ベースクラス構造関数コードを直接呼び出す.
(3)问:何がdelete pになってもpに値をつけることができますか...理解できないで、高い人の指点を求めますか??
答:deleteは削除ポインタpが指す例で、pポインタ自体は依然として存在し、delete後にpを空の値にするのが一般的で、空の値は一般的にNULLマクロと書かれていますが、実は0です.メモリ0の位置はアクセスが許可されていないため、delete 0操作コンパイラはエラー操作が実行されないと判断できるため、pを空の値0にするのは安全です.
(4)習慣を身につける:基類の析構は必ずvirtualである.
(5)ベースクラスポインタが派生クラスを指す場合、構造関数が虚関数として宣言されない場合、構造を解析する際に派生クラスの構造関数が呼び出されず、メモリが漏洩する.
(6)サブクラスオブジェクトの作成時に親コンストラクション関数を呼び出してからサブクラスコンストラクション関数を呼び出すと、オブジェクトをクリアするときに順序が逆になるのでdelete pは親のみをクリアし、サブクラスはクリアしません.
(7)ベースクラスオブジェクトのポインタまたは参照が派生クラスオブジェクトを呼び出す場合、ベースクラスの解析関数が虚解析関数でない場合、ベースクラスポインタまたは参照による派生クラスの解析は徹底していない.
後の言葉:
変更後のプログラム:
実行結果:
contructor Father!contructor Son!destructor Son!destructor Father!
#include
using namespace std;
class Father
{
public:
Father(){};
~Father(){};
};
class Son:public Father
{
public:
Son(){};
~Son(){};
};
int main()
{
Father *pfather=new Son;
delete pfather;
pfather=NULL;
return 0;
}
このプログラムはVC++6.0の実行後にエラーが発生していません.
上記の手順を次のように変更します.
#include
using namespace std;
class Father
{
public:
Father(){cout<<"contructor Father!"<
~Father(){cout<<"destructor Father!"<
};
class Son:public Father
{
public:
Son(){cout<<"contructor Son!"<
~Son(){cout<<"destructor Son!"<
};
int main()
{
Father *pfather=new Son;
delete pfather;
pfather=NULL;
return 0;
}
実行結果:
contructor Father!contructor Son!destructor Father!
派生クラスSonは解析されていないことは明らかであり,すぐにC++継承における虚解析関数の問題を引き出した.
(1)ベースクラスの構造関数が虚関数でない場合,ポインタを削除すると,そのクラスのメモリのみが解放され,派生クラスは存在しない.これでメモリが漏れました.
(2)構造関数が虚関数でない場合は,そのタイプの構造関数コードをポインタタイプで直接呼び出し,ポインタタイプがベースクラスであるため,ベースクラス構造関数コードを直接呼び出す.
(3)问:何がdelete pになってもpに値をつけることができますか...理解できないで、高い人の指点を求めますか??
答:deleteは削除ポインタpが指す例で、pポインタ自体は依然として存在し、delete後にpを空の値にするのが一般的で、空の値は一般的にNULLマクロと書かれていますが、実は0です.メモリ0の位置はアクセスが許可されていないため、delete 0操作コンパイラはエラー操作が実行されないと判断できるため、pを空の値0にするのは安全です.
(4)習慣を身につける:基類の析構は必ずvirtualである.
(5)ベースクラスポインタが派生クラスを指す場合、構造関数が虚関数として宣言されない場合、構造を解析する際に派生クラスの構造関数が呼び出されず、メモリが漏洩する.
(6)サブクラスオブジェクトの作成時に親コンストラクション関数を呼び出してからサブクラスコンストラクション関数を呼び出すと、オブジェクトをクリアするときに順序が逆になるのでdelete pは親のみをクリアし、サブクラスはクリアしません.
(7)ベースクラスオブジェクトのポインタまたは参照が派生クラスオブジェクトを呼び出す場合、ベースクラスの解析関数が虚解析関数でない場合、ベースクラスポインタまたは参照による派生クラスの解析は徹底していない.
後の言葉:
(1) , ,delete pfather Father , , main ,Son 。
(2) ? , , virtual, , , new , delete , , , , , 。
(3) , copy , 。
変更後のプログラム:
#include
using namespace std;
class Father
{
public:
Father(){cout<<"contructor Father!"<
virtual ~Father(){cout<<"destructor Father!"<
};
class Son:public Father
{
public:
Son(){cout<<"contructor Son!"<
~Son(){cout<<"destructor Son!"<
};
int main()
{
Father *pfather=new Son;
delete pfather;
pfather=NULL;
return 0;
}
実行結果:
contructor Father!contructor Son!destructor Son!destructor Father!