c++ 之类的前置声明
?
转自:http://blog.csdn.net/fjb2080/archive/2010/04/27/5533514.aspx?作者:清林,博客名:飞空静渡
刚开始学习c++的人都会遇到这样的问题:
定义一个类 class A,这个类里面使用了类B的对象b,然后定义了一个类B,里面也包含了一个类A的对象a,就成了这样:
?
????????????C&?doToC(C&);
????????????C&?doToC2(C&?c)?{return?doToC(c);};
从上面的代码来看,A的一个成员函数doToC2调用了另外一个成员函数doToC,但是无论是doToC2,还是doToC,它们的的参数和返回类型其实都是C的引用(换成指针,情况也一样),引用的赋值跟指针的赋值都是一样,无非就是整形的赋值,所以这里即不需要知道C的大小也没有调用C的任何函数,实际上这里并不需要C的定义。
但是,我们随便把其中一个C&换成C,比如像下面的几种示例:
??????????? 1.??? ??? ??? ??? C&?doToC(C&);
????????????C&?doToC2(C?c)?{return?doToC(c);};??? ?? ?? ?? ???
??? ?? ?? ?? ?? 2.
??????????? ??? C& doToC(C);
??????????? ??? C& doToC2(C& c) {return doToC(c);};
??? ?? ?? ?? ?? 3.
??? ?? ?? ?? ???C?doToC(C&);
??????????? ??? C& doToC2(C& c) {return doToC(c);};
??? ?? ?? ?? ?? 4.
??? ?? ?? ?? ?? C& doToC(C&);
??????????? ????C?doToC2(C& c) {return doToC(c);};
无论哪一种,其实都隐式包含了一个拷贝构造函数的调用,比如1中参数c由拷贝构造函数生成,3中doToC的返回值是一个由拷贝构造函数生成的匿名对象。因为我们调用了C的拷贝构造函数,所以以上无论那种情形都需要知道C的定义。
9和10都一样,我们都不需要知道C的定义,只是10的情况下,前置声明的语法会稍微复杂一些。
最后给出一个完整的例子,我们可以看到在两个不同名字空间的类型A和C,A是如何使用前置声明来取代直接包括C的头文件的:
A.h
#pragma once#include <list>#include <vector>#include <map>#include <utility> //不同名字空间的前置声明方式namespace test1{ class C;}namespace test2{ //用using避免使用完全限定名 using test1::C; class A { public: C useC(C); C& doToC(C&); C& doToC2(C& c) {return doToC(c);}; private: std::list<C> _list; std::vector<C> _vector; std::map<C, C> _map; C* _pc; C& _rc; };}?
C.h
#ifndef C_H#define C_H#include <iostream>namespace test1{ class C { public: void print() {std::cout<<"Class C"<<std::endl;} };}#endif // C_H?