相当于class 类名。
那么他和#include 包含头文件有什么区别呢
首先我们为什么要包括头文件问题的回答很简单通常是我们需要获得某个
类型的定义(definition)。那么接下来的问题就是在什么情况下我们才需要类
型的定义在什么情况下我们只需要声明就足够了问题的回答是当我们需要知
道这个类型的大小或者需要知道它的函数签名的时候我们就需要获得它的定
义。
假设我们有类型A和类型C在哪些情况下在A需要C的定义
 
1.A继承至C
2.A有一个类型为C的成员变量
3.A有一个类型为C的指针的成员变量
4.A有一个类型为C的引用的成员变量
5.A有一个类型为std::list<C>的成员变量
6.A有一个函数它的签名中参数和返回值都是类型C
7.A有一个函数它的签名中参数和返回值都是类型C它调用了C的某个函数
代码在头文件中
8.A有一个函数它的签名中参数和返回值都是类型C(包括类型C本身C的引
用类型和C的指针类型)并且它会调用另外一个使用C的函数代码直接写在
A的头文件中
9.C和A在同一个名字空间里面
10.C和A在不同的名字空间里面
1没有任何办法必须要获得C的定义因为我们必须要知道C的成员变量
成员函数。
2需要C的定义因为我们要知道C的大小来确定A的大小但是可以使用Pimpl
惯用法来改善这一点详情请
看Hurb的Exceptional C++。
34不需要前置声明就可以了其实3和4是一样的引用在物理上也是一
个指针它的大小根据平台不同可能是32位也可能是64位反正我们不需要
知道C的定义就可以确定这个成员变量的大小。
5不需要有可能老式的编译器需要。标准库里面的容器像list vector
map
在包括一个list<C>vector<C>map<C, C>类型的成员变量的时候都不需要

C的定义。因为它们内部其实也是使用C的指针作为成员变量它们的大小一开
始就是固定的了不会根据模版参数的不同而改变。
6不需要只要我们没有使用到C。
7需要我们需要知道调用函数的签名。
88的情况比较复杂直接看代码会比较清楚一些。
 
            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

QT_FORWARD_DECLARE_CLASS的更多相关文章

  1. Qt全局宏和变量

    1.  Qt 全局宏定义 Qt版本号: QT_VERSION :  (major << 16) + (minor << 8) + patch 检测版本号: QT_VERSION ...

随机推荐

  1. java实现邮箱找密码

    SMTP,POP3,IMAP POP3 POP3是Post Office Protocol 3的简称,即邮局协议的第3个版本,它规定怎样将个人计算机连接到Internet的邮件服务器和下载电子邮件的电 ...

  2. hashMap遍历方式

    package Ch17; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java ...

  3. jmeter系列-------脚本调试

    1.调试的时候 可以只跑需要调试的接口,禁用其他的接口 2.每个接口都需要增加断言眼,保证脚本的结果的正确性 3.验证脚本的可靠性,可以切换用户(测试变量)来进行调试 4.使用Debug Sample ...

  4. Maven maven-compiler-plugin版本

    项目执行Maven clean后出现WARNING提示.报如信息如下,根据报错信息 'build.plugins.plugin.version' for org.apache.maven.plugin ...

  5. 九九乘法表实现---基于python

    # coding:utf-8"""九九乘法表"""for k in range(1,10):    for i in range(1,k+1 ...

  6. Maven Scope取值的含义

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt257 maven依赖关系中Scope的作用 Dependency Scope ...

  7. Spring中ApplicationContext加载机制

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp33 加载器目前有两种选择:ContextLoaderListener和Co ...

  8. poj 1149经典网络流构图

    题意:m个猪圈,n个客户,每个客户给出选则猪圈的钥匙和需要购买猪的个数,其中每次客户购买时客户选则的猪圈数量可以相互更换,问最大购买数量. 思路:以客户作为除源点汇点之外的点,然后对于每个猪圈从源点连 ...

  9. hdu 2503 1713 1108 最小公倍数&最大公约数

    gcd模板: __int64 gcd(__int64 a,__int64 b) { retur b==0?a:gcd(b,a%b); } 1108: #include<iostream> ...

  10. linux一周学习总结

    对于linux,之前也完全没有接触过,完全零基础小白.来到马哥以后,进入学习也有一周时间 ,一周里老师带我们学习了很多指令,下面,我就自己的理解和老师讲授的内容对linux中的一些指令做一个简单的小总 ...