原文鏈接http://www.cnblogs.com/weixliu/p/3957227.html
最近在改一個C++程序的時候碰到一條警告信息,警告信息為:“
刪除指向不完整“Q2DTorusNode”類型的指針;沒有調用析構函數
1> c:\users\lxw\desktop\dragonfly第二階段實驗\最終的實驗版本\實驗目錄\dragonfly_modify\src\Q2DTorus.h(6) : 參見“Q2DTorusNode”的聲明
”
警告信息很是奇怪,其實出於強迫症的原因想要解決掉這個警告信息,而且從警告信息來看,程序也應該存在內存泄露的問題,因為警告直接明白告訴你了,沒有調用析構函數,接下來就是我解決的過程。我會搭建一個簡單的程序來模擬這個錯誤,因為程序是在有些多~
警告的來源:
一個頭文件A.h包含class A的代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#ifndef AH
#define AH
class
B;
class
A {
B *memb;
A() {
}
~A() {
delete
memb;
}
};
#endif
|
一個頭文件B.h包含class B的代碼如下:
1
2
3
4
5
6
|
#ifndef BH
#define BH
class
B {
};
#endif
|
此時編譯就會產生類似上面的警告信息:warning C4150: 刪除指向不完整“B”類型的指針;沒有調用析構函數。
原因分析:
因為class A中B的聲明依賴於class B的前置聲明,而不是#include "B.H",所以B的定義對A來說不可見,所以無法調用析構函數,導致內存泄露。
程序的變化
此時如果class A和class B相互保持對方類型的成員會如何呢?
A.h的代碼:
1
2
3
4
5
6
7
|
#ifndef AH
#define AH
class
B;
class
A {
B b;
};
#endif
|
B.h的代碼:
1
2
3
4
5
6
7
|
#ifndef BH
#define BH
#include "A.h"
class
B {
A a;
};
#endif
|
這段代碼存在問題,因為如果靜態定義對象A,B,此時必定存在一個對象的定義對於另外一個對象的定義不可見,所以定義失敗。如果均是利用#include對方,取決於編譯器的順序必定一個定義不可見。然而前置聲明不能定義對象。
解決方案:
此種狀況的解決利用前置聲明定義的那個類中的保持另外一個類的引用定義為指針,定義指針時不需要對那個類的定義可見。
另外的問題:
A.h
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#ifndef AH
#define AH
class
B;
class
A {
B* b;
void
setB() {
b->haha();
}
~A() {
delete
b;
}
};
#endif
|
B.h
1
2
3
4
5
6
7
8
9
10
|
#ifndef BH
#define BH
#include "A.h"
class
B {
A a;
void
haha() {
}
};
#endif
|
但是利用前置聲明導致定義指針成員的類會出現最開始說的warning警告,因為定義不可見的原因。
“warning C4150: 刪除指向不完整“B”類型的指針;沒有調用析構函數”
而且另外的一個問題是在該.h文件中不能使用該指針調用這個類的成員,原因也是定義不可見。
“error C2227: “->haha”的左邊必須指向類/結構/聯合/泛型類型”
解決方案:
此時需要將A.h的所有成員函數實現重新定義一個.cpp文件,然后該.cpp文件去#include 指針成員類的頭文件聲明,此時定義可見,即可定義析構函數,調用指針的類成員了。
A.h
1
2
3
4
5
6
7
8
9
10
|
#ifndef AH
#define AH
class
B;
class
A {
public
:
B* b;
void
setB();
~A();
};
#endif
|
B.h
1
2
3
4
5
6
7
8
9
10
11
|
#ifndef BH
#define BH
#include "A.h"
class
B {
public
:
A a;
void
haha() {
}
};
#endif
|
A.cpp
1
2
3
4
5
6
7
8
|
#include "A.h"
#include "B.h"
A::~A() {
delete
b;
}
void
A::setB() {
b->haha();
}
|
問題到此就解決完畢了~