前两天因为修改自己文章《个人对QT中的namespace Ui的理解》遇到前置声明的概念,很陌生就好奇的自己码了点代码,谁知编译报错,改来改去却百思不得其解。代码如下:
#includeusing namespace std; class SayHi; int main() { SayHi * stu = new SayHi; cout<<"Hello!"< Say(); return 0; } class SayHi { public: SayHi() {}; void Say() { cout << "Hi" << endl; } };
编译报错为:
1> main.cpp
1>d:vs2015demo2demo2main.cpp(6): error C2512: “SayHi”: 没有合适的默认构造函数可用
1>d:vs2015demo2demo2main.cpp(8): error C2027: 使用了未定义类型“SayHi”
1> d:vs2015demo2demo2main.cpp(3): note: 参见“SayHi”的声明
1>d:vs2015demo2demo2main.cpp(8): error C2227: “->Say”的左边必须指向类/结构/联合/泛型类型
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========
我对类前置声明的理解是:如果在一处使用到一未定义的类时,只需在使用该类之前声明一下即可。刚开始我没定义构造函数,指望系统自己添加不带参的构造函数,但报错。可明明我定义了不带参的构造函数啊,为什么还报故呢?并且如果我将类的定义放到主函数之前,再编译运行就very good!这说明我类的定义没有问题。故感觉不对,应该哪里理解的不对,赶紧查资料。综合几篇文章,我明白了:C++的类应当是先定义,然后使用。但在处理相对复杂的问题、考虑类的组合时,很可能遇到俩个类相互引用的情况(这种情况称为循环依赖),这时就可以使用前置声明来解决问题。使用前置引用声明虽然可以解决一些问题,但它并不是万能的。需要注意的是,尽管使用了前置引用声明,但是在提供一个完整的类声明之前,不能定义该类的对象,也不能在内联成员函数中使用该类的对象。具体到我的这个例子,我错的地方是1、在未提供完整的类声明之前,在SayHi * stu = new SayHi这一句中用new SayHi来定义类的匿名对象并返回其指针给stu;2、SayHi类的对象未定义之前使用stu -> Say()。
C++的类可以进行前置声明。但是,仅仅进行前置声明而没有定义的类是不完整的,这样的类,只能用于定义指针、引用、以及用于函数形参的指针和引用。而不能定义对象(因为此时编译器只知道这是个类,还不知道这个类的大小有多大),也不能访问类的对象,任何形式的访问都不允许(因为此时根本不知道有些什么成员)。我的理解是,只有前置声明时,因为不能确定该类的数据结构和所占大小,所以无法提前分出一段内存空间预留给该类待定义后使用,故凡是涉及堆上内存分配(实例化对象、访问其对象的成员)的操作都是非法的。等到类正式定义以后,就可以以各种方式使用该类了。
前向声明的作用是:
1.不必在include头文件了,相对会省点编译时间。
2.方便的解决两种类类型互相使用的问题。针对接口编程常常会遇到这种互相使用类型的场景。
参考来源:
C++ 类的前向声明的用法 - 王陸 - 博客园 (cnblogs.com)
C++中类的前向声明的用法 - 飞翔雨 - 博客园 (cnblogs.com)



