コンストラクション関数、コンストラクション関数、および虚関数の関係
1384 ワード
まず2点を明らかにするコンストラクション関数を虚関数虚関数として定義することはできません.親参照またはポインタによって子クラスのメンバー関数を呼び出すことを目的としています.コンストラクション関数の目的は、オブジェクトを作成することです.サブクラスオブジェクトを作成すると、親のコンストラクション関数ではなく、サブクラスのコンストラクション関数が呼び出されます.子クラスのコンストラクション関数は、親クラスのコンストラクション関数を使用します.この順序は継承メカニズムとは異なる.したがって、子クラスは親クラスのコンストラクション関数を継承しないため、クラスのコンストラクション関数を虚関数として宣言することは意味がありません.これが理解できないなら覚えておけばいい. 親クラスの構造関数は、虚関数 であるべきである.
第2の点については、例Aが親であり、BがAの子であり、Bにchar*nameメンバーが追加され、nameはnewによって申請されたメモリを指す.Bクラスのオブジェクトが破棄されると、必ず~B()構造関数が呼び出されてメモリが解放されます.次のコードを参照してください.
Aの構造関数が虚関数として宣言されていない場合、delete aはデフォルトの静的アセンブリ、すなわちAの構造関数~A()を呼び出す.これにより、BクラスのA部分が指すメモリは解放されますが、新しいクラスメンバーが指すメモリ、すなわちBのnameメンバーが指すメモリブロックは解放されず、メモリ漏洩の問題が発生します.しかし、Aの解析関数が虚関数として宣言されると、Bの虚関数数テーブルでは、Aを指す解析関数のポインタ位置がBを指す解析関数に変更されます.delete aを呼び出すとBの構造関数が呼び出され、Bが指すメモリが解放され、Aの構造関数が呼び出され、Aが指すメモリが解放されます.口先だけで根拠がないから,例を見てからにしよう.
例1
このコードの実行結果:
Aの解析関数のみが実行され,Aが指すメモリは解放されたが,Bが指すメモリは解放されなかったことがわかる.我々はAの解析関数を虚関数として宣言する
次のように再実行されます.
プログラムはまずサブクラスの解析関数を呼び出し,Bが指すメモリを解放し,次に親クラスの解析関数を呼び出し,Aが指すメモリを解放する.
第2の点については、例Aが親であり、BがAの子であり、Bにchar*nameメンバーが追加され、nameはnewによって申請されたメモリを指す.Bクラスのオブジェクトが破棄されると、必ず~B()構造関数が呼び出されてメモリが解放されます.次のコードを参照してください.
A* a = new B;
...
delete a; // ,~A() ~B();
Aの構造関数が虚関数として宣言されていない場合、delete aはデフォルトの静的アセンブリ、すなわちAの構造関数~A()を呼び出す.これにより、BクラスのA部分が指すメモリは解放されますが、新しいクラスメンバーが指すメモリ、すなわちBのnameメンバーが指すメモリブロックは解放されず、メモリ漏洩の問題が発生します.しかし、Aの解析関数が虚関数として宣言されると、Bの虚関数数テーブルでは、Aを指す解析関数のポインタ位置がBを指す解析関数に変更されます.delete aを呼び出すとBの構造関数が呼び出され、Bが指すメモリが解放され、Aの構造関数が呼び出され、Aが指すメモリが解放されます.口先だけで根拠がないから,例を見てからにしよう.
例1
#include
using namespace std;
class A {
public:
~A() {
cout<
このコードの実行結果:
A::~A()
Aの解析関数のみが実行され,Aが指すメモリは解放されたが,Bが指すメモリは解放されなかったことがわかる.我々はAの解析関数を虚関数として宣言する
virtual ~A() {
cout<
次のように再実行されます.
B::~B()
A::~A()
プログラムはまずサブクラスの解析関数を呼び出し,Bが指すメモリを解放し,次に親クラスの解析関数を呼び出し,Aが指すメモリを解放する.