c++ 前向申明(ForwardDeclaration)待整理
1、c++的#include的预编译
#后是指令关键字,在关键字和#号之间允许存在任意个数的空白字符。整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。#include预处理指令的作用是在指令处展开被包含的文件。展开被包含的文件之后,代码就可以正常地调用该文件中所声明的变量和函数。#include指令有两种使用方法:第一种:#include <xxx.h> 第二种:#include "xxx.h"。
第一种方法将待包含的头文件使用尖括号括起来,预处理程序会在系统默认目录或者括号内的路径查找,通常用于包含系统中自带的公共头文件。
第二种方法将待包含的头文件使用双引号引起来,预处理程序会在程序源文件所在目录查找,如果未找到则去系统默认目录查找,通常用于包含程序作者编写的私有头文件。
2、c++中的单独编译
-
首先,我们可以将所有东西都放在一个.cpp文件内,然后编译器就将这个.cpp编译成.obj。就是编译单元了,一个程序,可以由一个编译单元组成,也可以有多个编译单元组成.。如果你不想让你的源代码变得很难阅读的话,就请使用多个编译单元吧(一个函数不能放到两个编译单元里面,但两个以上就可以分别放在一个单元,也就是cpp里面)。那么就是一个.cpp对应一个.obj,然后将所有的obj链接起来(通过一个叫链接器的程序),组成一个.exe,也就是程序了。如果一个.cpp要用到另一个.cpp定义的函数怎么办? 只需在这个.cpp种写上他的函数声明就可以了。其余工作由链接器帮你完成,你可以随便调用该函数。
-
c++程序预编译和链接阶段是分开的,更加详细需要了解编译原理,声明仅仅是将一个符号引入到一个作用域。而定义提供了一个实体在程序中的唯一描述。在一个给定的定义域中重复声明一个符号是可以的 , 但是却不能重复定义 , 否则将会引起编译错误。在编译时,编译器只检测程序语法和函数、变量是否被声明。如果函数未被声明,编译器会给出一个警告,但可以生成目标文件。而在链接程序时,链接器会在所有的目标文件中找寻函数的实现。如果找不到,那到就会报链接错误码( Linker Error)。在 VC 下,这种错误一般是: Link 2001 错误,意思说是说,链接器未能找到函数的实现。链接把不同编译单元产生的符号联系起来。有两种链接方式:内部链接和外部链接。
3、c++中的前向声明以及两个类相互包含引用问题
- 前向声明:可以声明一个类而不定义它。这个声明被称为前向声明(forward declaration)。例如:class name。在声明之后,定义之前,类name是一个不完全类型(incompete type),即已知name是一个类型,但不知道包含哪些成员。不完全类型只能以有限方式使用,不能定义该类型的对象,不完全类型只能用于定义指向该类型的指针及引用,或者用于声明(而不是定义)使用该类型作为形参类型或返回类型的函数。
类的前向声明只适用于指针和引用的定义,如果是普通类类型就得使用include了。 - 两个类之前的相互引用包含问题。
在构造自己的类时,有可能会碰到两个类之间的相互引用问题,例如:定义了类A类B,A中使用了B定义的类型,B中也使用了A定义的类型。
class A { int i; B b; } class B { int i; A* a; }
请注意上面的定义内容,一般情况下是不能出现类A,类B相互引用都定义对象,即如下的样子:
class A { int i; B b; } class B { int i; A a; }
在这种情况下,想想能够有a.b.a.b.a.b.a.b.a.b…………,很有点子子孙孙无穷尽之状,那么我的机器也无法承受。最主要的还是这种关系很难存在,也很难管理。这种定义方式类同程式中的死循环。所以,一般来说,两者的定义,至少有一方是使用指针,或两者都使用指针,但是决不能两者都定义实体对象。
//class A.h #include "B.h" class A { int i; B b; } //class B.h class A; class B { int i; A *a; } //B.cpp //在B.cpp中的文档包含处要有下面语句,否则不能调用成员a的任何内容 #include "A.h" B::B() { …… }