CODE_C2

函数内联

  1. 函数内联,其目的是为了提高函数的执行效率。
  2. 关键字Inline必须与函数体放在一起才能够使函数成为内联,仅将inline放在函数声明前面不起任何作用。
  3. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    //错误 
    inline void Foo(int a,int b);
    //正确
    void Foo(int a,int b);
    inline void Foo(int a,int b)
    {

    }
    //内联,不提倡
    class A
    {
    public :
    void Foo(int a)
    {
    }
    };
    //内联,提倡
    class A
    {
    public :
    void Foo(int a);
    }
    inline void A::Foo(int a)
    {
    }
  4. 慎用内联,内联是以代码膨胀为代价的,仅仅省去了函数调用的开销

  5. 内联的工作方式。对于任何内联函数,编译器在符号表中放入函数的名称、返回值、参数等。如果内联函数没有错误,整个函数体也会被放到符号表中。在进行内联函数的调用时,编译器首先会检查调用是否安全,如果安全的话,内联函数的代码就会直接替换为函数调用,从而省去了函数调用的开销。
  6. 不宜使用内联的情况
    • 函数体内的代码过长。
    • 函数体内出现循环

      编程是多费了一些心思,少了一些痛快,这才是编程的艺术。

      构造、析构、拷贝、赋值

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
          #include <iostream>
      #include <cstring>
      using namespace std;

      class String
      {
      public:
      String(char *str=NULL);
      String(const String &other);
      String& operator =(const String &other);
      ~String(void);
      private:
      char *m_Data;
      };

      String::String(char *str)
      {
      if(str==NULL)
      {
      m_Data=new char[1] ;
      *m_Data='\0';
      }
      else
      {
      m_Data=new char[strlen(str)+1];
      strcpy(m_Data,str);
      }
      }
      String::String(const String &other)
      {
      m_Data=new char[strlen(other.m_Data)+1];
      strcpy(m_Data,other.m_Data);
      }

      String& String::operator =(const String &other)
      {
      if(this==&other)
      return *this;
      delete [] m_Data;
      m_Data=new char[strlen(other.m_Data)+1];
      strcpy(m_Data,other.m_Data);
      return *this;
      }
      String::~String()
      {
      delete [] m_Data;
      }

      int main()
      {
      return 0;
      }

对于任意一个类,C++编译器会自动为类产生四个缺省的函数:构造函数、析构函数、拷贝函数、赋值函数。

一只公鸡使劲地追赶一只刚刚下蛋的母鸡,因为母鸡下了鸭蛋。

.h .gch文件

  1. 概念
    • gch即预编译头,将头文件预编译为二进制代码后后续编译使用。当多个源文件包含一个头文件,正常流程是将其在每个源文件中解析一遍,造成重复浪费。使用gch,将头文件作预编译头形成中间处理的二进制代码,然后再包含进源文件中。
  2. 适用
    • gch适用于被多个源文件包含的头文件,且头文件不会经常做修改。
  3. 注意
    • gch提高了编译速度,但需要注意在默认情况下gch不会因为头文件的更新而更新,从而在编译过程中形成一个不容易发现的坑。需要将头文件和gch设置为依赖关系。

      C工程

  4. .h文件叫做头文件,不能够被编译。”#include”叫做编译预处理指令,可以简单理解成,在1.cpp中的”#include 1.h”指令把1.h中的代码在编译前添加在了1.cpp的头部。
  5. 每个.cpp文件都会被编译,生成一个.obj文件,然后所有的.obj文件链接所有的.obj文件链接起来,可执行文件就生成了。
  6. c语言和c++都是这样的,声明和定义要分开。要想使用的话需要使用extern

    pragma once 与 ifndef

  7. pragma once 是新兴的防止头文件被重复包含的语句。两者区别见pragma once 与 ifndef的区别
  8. if 与 else 匹配问题
    是完全不同的两个运行结果。原因是作用域的问题。
  9. 为什么使用using namespace std;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #include <iostream.h>非标准输入输出流
    #include <iostream>标准输入输出流

    C++中为了避免名字定义冲突,特别引入了“名字空间的定义”,即namespace
    当代码中用<iostream.h>时,输出可直接引用cout<<x;//<iostream.h>继承C语言的标准库文件,未引入名字空间定义,所以可直接使用。
    当代码中引入<iostream>时,输出需要引用std::cout<<x;如果还是按原来的方法就会有错。
    使用<iostream>时,引入std::有以下方法:

    1.
    using namespace std;
    cout<<x;
    2.
    using std::cout;
    cout<<x;
    3.
    最基本的std::cout<<x;

    这回你该知道为什么通常用#include <iostream>时,
    要用using namespace std;了吧。如果你不用这个,就要在使用cout时,用后两种方法了。
    其他头文件也是同样的道理。
    (有“.h”的就是非标准的,C的标准库函数,无“.h”的,就要用到命令空间,是C++的。还有一部分不完全是有“.h”和没“.h”的差别。例如:math.h和cmath)
  10. 为什么在c++程序里可以直接用printf 和scanf

    • iostream是没有包含C语言中的输入输出函数的,这个头文件是C++中输入输出流的,你那种情况一般是编译环境默认连接了stdio.h造成的。那是不是要用c的输入输出加上<stdio.h>比较安全?是不是所有编译器都支持这种连接呢?应该是的,头文件的默认添加可以在编译环境中设置。不过原则上是应该加上相应的头文件的,一般还加上头文件比较好。