设为首页 加入收藏

TOP

函数实现不放在头文件的原因(三)
2012-12-10 12:47:23 来源: 作者: 【 】 浏览:757
Tags:函数 实现 放在 文件 原因

 

    2.2 着手

    解决的办法有两个,各自为两个关键字,一个是 inline ,另一个是 static .使用这两个关键字的任意一个来修饰 integer_add 函数,都会消除上述的冲突问题,然而本质却大不相同.

    如果使用 inline ,则意味着编译器会在调用此函数的地方把函数的目标代码直接插入,而不是放置一个真正的函数调用,实际作用就是这个函数事实上已经不再存在,而是像宏一样被就地展开了.使用 inline 的副作用,首先在于毋庸置疑地,代码的体积变大了;其次则是,这个关键字严格算起来并不是 C 语言的关键字,使用它多少会带来一些移植性方面的风险,尽管主流的 C 语言编译器都可以支持 inline .对于 GCC , inline 功能关键字就是 inline 本身,而对于微软的编译器,应该是 __inline (注意有两个前导下划线).而且,根据惯例, inline 通常都是对编译器的某种暗示而非强制要求,编译器有权力在你不知情的情况下把它实现为非 inline 的状态(可能的原因有,函数太大或者复杂度过高).这样的后果是什么,不好意思,我没有测试过.

    如果是使用 static ,那么至少结果是可预料的.所有包含此头文件的源文件中都会存在此函数的一份副本.虽然代码也有一定程度的膨胀,但好就好在互相不冲突,因为 static 关键字保证了该函数的可见度为单个源文件之内.

    以上的讨论虽然看起来主要聚焦在 C 语言上,但由于 C++(www.cppentry.com) 是 C 语言的超集,并且在这些方面并没有做太多的修改,因此讨论结果同样也适用于 C++(www.cppentry.com) .

    2.3 继续

    对于 C 语言来讲,上面的改进几乎已经走到了尽头,没有继续发展的余地.然而对于 C++(www.cppentry.com) 则不同,我们还可以进一步把它做得更漂亮.

    首先,我们做以下的改动:

    [cpp]

    class Integer

    {

    public:

    int add(int a, int b)

    {

    return a + b;

    }

    };

    这样的形式,几乎连 C++(www.cppentry.com) 的初学者都能看出来,确实不会再发生链接冲突的问题了.不过也有一个问题,我们如果要计算两个整数的和的话,需要这样写:

    Integer op;

    op.add(i, j);

    而这显然不是一种可接受的状态,之前很简单的一条函数语句的调用,现在却必须定义一个类的对象实例.于是我们再次求助于 static ( inline 是不适用的,因为它不能去掉定义对象实例这一步,而且事实上,把实现写到类定义之内的函数缺省就是 inline 的).现在,类就像这个样子:

    [cpp]

    class Integer

    {

    public:

    static int add(int a, int b)

    {

    return a + b;

    }

    };

    调用方式也相应地简化为:

    Integer::add(i, j);

    尤其需要注意的就是这里, C++(www.cppentry.com) 类中的 static 函数和全局 static 函数的行为是有差异的,它编译之后仅产生一份实现代码,并不会由于被多个源文件包含而产生多份副本 .

    这距离我们的终极目标已经不远了(我们的终极目标是: add(i, j) 就可以搞定).于是我们再次高举起宏这杆大旗,在头文件里添加以下定义:

    #define integer_add         Integer::add(后注:突然想到,似乎定义 const 函数指针也可以达到相同的目的)

    上面解决的其实仅仅是 C++(www.cppentry.com) 中全局函数的头文件复用问题,那么类呢 类的情况要复杂一些.如果是 static 方法,那么正好是和上述我们对全局函数的变通实现是一致的;如果是 inline 的方法(不管有没有 inline 关键字),则其状态几乎理论上等同于前面所述的 inline 全局函数的情况.那么还有最后的一种情况, virtual函数.对于 virtual 函数,我们等到的是一个好消息:它总是生成一份代码(甚至你显式使用 inline 关键字修饰) .这里面有个玄机: virtual 函数的地址会被写到类的 v-table 里,是要能够在运行期被调用的(其核心在于,其调用者以及调用时机在编译时是不明确的),所以绝对不能生成为全部就地展开的形式.以此可以做一个推论:所有会被求址的成员函数,都会生成一份函数实体,而不能单纯地去符合内联的修饰关键字.

    3 、后记

    当然,把实现全部放在头文件中并不是万金油,不是放之四海而皆准的准则,正如本文开头所说,这仅仅是一种选择,只不过你之前没有想到过可以这么做,而现在知道了.它最适合的场合是一些规模较小的工具类的实现.

      

首页 上一页 1 2 3 下一页 尾页 3/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇12年长春区域赛-C题 下一篇C语言中数据结构小练习

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: