zoukankan      html  css  js  c++  java
  • effective c++:inline函数,文件间编译依存关系

    inline函数

    inline函数可以不受函数调用所带来的额外开销,编译器也会优化这些不含函数调用的代码,但是我们不能滥用Inline函数,如果程序中的每个函数都替换为inline函数那么生成的目标文件会急剧增加,当我们运行这个程序时会占用机器大量的内存,所以我们一般把本体很小的函数替换为Inline(一般10行以内)。

    inline只是对编译器的申请,并不是强制执行,比方在class定义式内定义成员函数,如下所示

    class Person {
    public:
      ...
      int age() const { return theAge; } // an implicit inline request: age is
      ... // defined in a class definition
    private:
      int theAge;
    };

    age()便被隐喻声明为inline.

    而对于virtual函数,由于他需要在运行时决定调用哪个函数,所以即便是声明虚函数为Inline,编译器也会拒绝这个请求。

    在构造函数和析构函数上使用Inline貌似可行,因为他们的函数体大多不长,甚至不含代码,但是这往往是个假象。

    Derived::Derived() // conceptual implementation of
    { // “empty” Derived ctor
      Base::Base(); // initialize Base part
      try { dm1.std::string::string(); } // try to construct dm1
      catch (...) { // if it throws,
        Base::~Base(); // destroy base class part and
        throw; // propagate the exception
      }
      try { dm2.std::string::string(); } // try to construct dm2
      catch(...) { // if it throws,
        dm1.std::string::~string(); // destroy dm1,
        Base::~Base(); // destroy base class part, and
        throw; // propagate the exception
      }
      try { dm3.std::string::string(); } // construct dm3
      catch(...) { // if it throws,
        dm2.std::string::~string(); // destroy dm2,
        dm1.std::string::~string(); // destroy dm1,
        Base::~Base(); // destroy base class part, and
        throw; // propagate the exception
      }
    }

    这就是所谓空的构造函数实际产生的代码,它一定会调用成员变量和base构造函数等。

    对于需要调试的程序,Inline函数的存在会对调试造成很大障碍,毕竟断电不能设在并不存在的函数内。

    所以对于Inline函数一开始设计程序时尽量少的使用,当有需求时再使用也不迟。

    文件间编译依存关系

     当我们对c++程序的某个实现文件做了轻微的修改,然后重新建置这个程序,并预计只花数秒就好,当按下“Build”或键入make,整个项目都被重新编译连接了。这个问题出在c++并没有将接口与实现分离。

    #include <string>
    #include "date.h"
    #include "address.h"
    
    class Person {
    public:
      Person(const std::string& name, const Date& birthday,
      const Address& addr);
      std::string name() const;
      std::string birthDate() const;
      std::string address() const;
      ...
    private:
      std::string theName; // implementation detail
      Date theBirthDate; // implementation detail
      Address theAddress; // implementation detail
    };

     如同上述类的定义,如果这些头文件被修改,那么含入它的文件也一定会被重新编译,这就造成了文件间的编译依存关系。

    class Date; // forward declaration
    class Address; // forward declaration
    class Person {
    public:
      Person(const std::string& name, const Date& birthday,
      const Address& addr);
      std::string name() const;
      std::string birthDate() const;
      std::string address() const;
      ...
    };

     我们可以通过前置声明使得Person只有在Person头文件被修改时才被重新编译。但他同样存在问题

    int main()
    {
      int x; // define an int
      Person p( params ); // define a Person
      ...
    }

     当编译器看到p时就必须给他分配足够放Person的空间,它也只有访问类的定义式来获取这一信息,我们需要将对象的实现隐藏于指针背后。书中对于这一问题提出了两种设计方案:handle classes和interface classes。对于这两中实现比较陌生,所以等以后透彻理解它们之后再补充本文。

  • 相关阅读:
    TongJI Online Judge预赛(3): Game
    堆栈小应用:配对
    在.net中使用Udp协议创建简单的聊天程序
    TongJI Online Judge预赛(2): LOVE LETTER
    全排列问题之递归求解
    如何打造RSS阅读器
    Html 常用标志总结
    实现页面的分帧显示
    每天OnlineJudge之 “数素数”
    文本编辑器中,如何设计 撤销/重复栈
  • 原文地址:https://www.cnblogs.com/loujiayu/p/3629296.html
Copyright © 2011-2022 走看看