BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / cpp / #28562同步于 2009/9/16
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖

问一个关于类的前置声明的问题

fox1987
2009/9/16镜像同步11 回复
为了省事,在一个专门的头文件里前置声明了所有要用的类, 然后后面每个类包含要用到的其他类的头文件和那个专门的前置声明的头文件。。。 但是程序编译的时候提示了warning:no destructor called 就是说这个类要调用到另一个类的析构函数的时候他找不到析构函数(网上找的解释) 一下网上找的这个描述。。不知道能描述清楚不。。 Warning C4150 Deletion of pointer to incomplete type 'type'; no destructor called 下面的代码会导致这个问题: class A; A *pA = new A(); delete pA; // Warning C4150 这个Warning字面的意思是由于类型是不完全类型(Incomplete Type),因此destructor不会被调用。 其原因是由于前面使用前置声明来声明class A,此时class A并没有完整的定义,编译器只是把A加入到符号表并标记A为一个class,编译器并不知道更多的信息,比如A的大小,有何成员函数等等。在以一般情况下,如果我们只用到A的指针,在特定平台下A的指针大小固定,因此编译器不会报任何错误。然而,在调用delete来删除pA的时候,编译器可以知道pA所指的内存大小,因为内存分配器在内存块中保存了大小信息,可以正确释放A所占据的内存。但是,由于A是Incomplete Type,编译器无法知道A所对应的析构函数(destructor),因此不会调用A的析构函数。 解决方法很简单,#include A所在的头文件即可,如果忘记了#include,则会出现此Warning。 当然了,还有一种情况是你已经在某个地方调用过A的析构函数了(这种情况不太常见),在这里只需要释放内存即可,所以可以这么写: class A; A *pA = new A(); delete (void *)pA; 就是这个,但是我试了第一种方式没解决,第二种倒是不提示了,但是程序还没写完,不知道会不会有潜在的问题,有没有遇到过这种问题的啊。。-- ◢██◤ ◢██◣ ◥◣ ◢◤ ◢█ ◢██◣ ◢██◣ ◢██◣ █ █ █ ◥◣◢◤ █ █ █ █ █ █ ███◤ █ █ ██ █ ◥███ ████ █ █ █ █ ◢◤◥◣ █ ◣ █ █ █ █ █ ◥██◤ ◢◤ ◥◣ █ ◥██◤ ◥██◤ █
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
kmplayer机器人#1 · 2009/9/16
同不懂,帮顶.
abobo机器人#2 · 2009/9/16
visualbupt机器人#3 · 2009/9/16
BDing
shenlei机器人#4 · 2009/9/16
可能你已经在某个地方调用过析构函数了仔细找找别的地方的代码?
jmpesp机器人#5 · 2009/9/16
【 在 fox1987 的大作中提到: 】 : 为了省事,在一个专门的头文件里前置声明了所有要用的类, : 然后后面每个类包含要用到的其他类的头文件和那个专门的前置声明的头文件。。。 : 但是程序编译的时候提示了warning:no destructor called : ................... 第一种方法是可以解决问题的。 至于第二种,必然是会出现问题的,除非你显式调用A类的析构函数,不然A类的析构函数将不被调用,这样如果是在析构中负责内存释放的时候,就会出现内存泄露了。 注意,正常情况下,编译器如果发现delete的是类指针,便会在释放内存之前编译器自动调用类的析构函数。
fox1987机器人#6 · 2009/9/17
【 在 jmpesp 的大作中提到: 】 : 第一种方法是可以解决问题的。 : 至于第二种,必然是会出现问题的,除非你显式调用A类的析构函数,不然A类的析构函数将不被调用,这样如果是在析构中负责内存释放的时候,就会出现内存泄露了。 : 注意,正常情况下,编译器如果发现delete的是类指针,便会在释放内存之前编译器自动调用类的析构函数。 我就是第一种把用的头文件放进去了,还是没用。。所以郁闷了
jmpesp机器人#7 · 2009/9/17
【 在 fox1987 的大作中提到: 】 : 我就是第一种把用的头文件放进去了,还是没用。。所以郁闷了 你注意下文件头顺序,或者你忽略了什么其他东西。第一种方法是可以的。
fox1987机器人#8 · 2009/9/18
【 在 jmpesp 的大作中提到: 】 : 你注意下文件头顺序,或者你忽略了什么其他东西。第一种方法是可以的。 头文件顺序? 那么前置申明所有类的的头文件和使用到得类的头文件都要被包含的时候哪个应该在前啊?
hong机器人#9 · 2009/9/18
只要是出现delete的那个类之前有它想delete的类型的完整定义就行了 比如说 //class1.h #ifndef CLASS1_H #define CLASS1_H #include <iostream> using namespace std; class Class1 { public: ~Class1(){ cout<<"in ~Class1()"<<endl; } }; #endif //class2.h #ifndef CLASS2_H #define CLASS2_H #include <iostream> using namespace std; class Class1; class Class2 { public: Class2(Class1* p):p(p){} ~Class2(){ cout<<"in ~Class2()"<<endl; if(p!=NULL) delete p; } private: Class1* p; }; #endif //test.cpp #include "class1.h" //包括了class1的完整定义 #include "class2.h" //class2在前将出现问题.导致class1的析构调不到 int main() { Class1* pobj1=new Class1; Class2 obj2(pobj1); return 0; }