在编写C++程序的时候,偶尔需要用到前置声明(Forward declaration)。下面的程序中,带注释的那行就是类B的前置说明。这是必须的,因为类A中用到了类B,而类B的声明出现在类A的后面。如果没有类B的前置说明,下面的程序将不同通过编译,编译器将会给出类似“缺少类型说明符”这样的出错提示。
代码一: // ForwardDeclaration.h #include <iostream> using namespace std; class B; // 这是前置声明(Forward declaration) class A { private: B* b; public: A(B* b):b(b){} }; class B { }; // Main.cpp #include "ForwardDeclaration.h" int main(int argc, char** argv) { B* b = new B(); A* a = new A(b); delete a; delete b; return 0; }
上面程序可以顺利编译和运行(几乎没有做什么,也没有输出)。
是不是有了前置说明就万事大吉了呢?我们看看下面的代码(1是新增加的):
代码二: // ForwardDeclaration.h #include <iostream> using namespace std; class B; // 这是前置声明(Forward declaration) class A { private: B* b; public: A(B* b):b(b){} void someMethod() { b->someMethod(); // (1) } }; class B { public: void someMethod() { cout << "something happened..." << endl; } }; // Main.cpp #include "ForwardDeclaration.h" int main(int argc, char** argv) { B* b = new B(); A* a = new A(b); a->someMethod(); delete a; delete b; return 0; }
一编译,发现代码(1)处出错。出错提示往往包括(不同的编译器给出的提示会有所不同):
\1. 使用了不完整的类型B;
\2. “->somemethod”的左边必须指向类/结构/联合/泛型类型
原因:
\1. (1)处使用了类型B的定义,因为调用了类B中的一个成员函数。前置声明class B;仅仅声明了有一个B这样的类型,而并没有给出相关的定义,类B的相关定义,是在类A后面出现的,因此出现了编译错误;
\2. 代码一之所以能够通过编译,是因为其中仅仅用到B这个类型,并没有用到类B的定义。
解决办法是什么?
将类的声明和类的实现(即类的定义)分离。如下所示:
// ForwardDeclaration.h 类的声明 #include <iostream> using namespace std; class B; // 这是前置声明(Forward declaration) class A { private: B* b; public: A(B* b); void someMethod(); }; class B { public: void someMethod(); }; // ForwardDeclaration.cpp 类的实现 #include "ForwardDeclaration.h" A::A(B* b):b(b) { } void A::someMethod() { b->someMethod(); } void B::someMethod() { cout << "something happened..." << endl; } // Main.cpp #include "ForwardDeclaration.h" int main(int argc, char** argv) { B* b = new B(); A* a = new A(b); a->someMethod(); delete a; delete b; return 0; }
结论:
前置声明只能作为指针或引用,不能定义类的对象,自然也就不能调用对象中的方法了。
而且需要注意,如果将类A的成员变量B* b;改写成B& b;的话,必须要将b在A类的构造函数中,采用初始化列表的方式初始化,否则也会出错。