又是好久没有更新了,家人们,主播最近写完了c++的几个轮子项目,工程能力有了一内内的提高,现在在准备八股,希望暑假or大三能找到一个满意的实习吧(虽然就目前来看,c++全是劝退,我真服了,后悔没有选java了,后面主播慢慢转go吧)

在C++中,inline 关键字主要用于定义内联函数,具有以下两个主要作用:

  1. 优化性能
    使用 inline 修饰的函数,建议编译器在调用该函数时,将函数体的代码直接插入到调用点。

    相比正常的函数调用过程:寄存器保存,参数压栈,跳转到函数地址,执行函数体,返回并恢复寄存器

    这可以减少函数调用的开销,尤其适用于小型、频繁调用的函数。例如:

    1
    inline int square(int x) { return x * x; }

    当调用 square(5) 时,编译器可能将代码替换为 5 * 5,避免函数调用开销。
    注意inline 只是建议,编译器可能忽略它,尤其在以下情况下:

    • 函数体过大
    • 函数包含循环、递归、静态变量、switch 或 goto 语句
    • 函数地址被取用(如通过函数指针)
  2. 允许多个定义
    inline 函数可以在头文件中定义,并被多个编译单元(.cpp 文件)包含,而不会导致链接错误(违反“单一定义规则”)。这是因为 inline 函数允许多个相同的定义,链接器会选择一个定义并丢弃其他重复定义。
    示例:

    1
    2
    // example.h
    inline int add(int a, int b) { return a + b; }

    多个 .cpp 文件包含此头文件时,不会引发重定义错误。

看到第二个作用,主播不禁想到了自己在项目开发的过程中,hpp文件那是嘎嘎重复被cpp文件使用啊(虽然有#program once),而头文件中的类中难免有一些成员函数是直接定义在类里面的,那为什么没有事呢。

(正常情况下,函数只能在头文件中声明,而不能在头文件中定义)

1. 类内函数的内联特性

  • 隐式内联

    • 在类定义中直接定义的成员函数(包括普通成员函数、构造函数、析构函数等)默认是 inline 函数,无需显式使用 inline 关键字。

    • 这是 C++ 标准规定的行为,原因是为了方便在头文件中定义类时,允许函数体直接嵌入类定义,而不会违反单一定义规则(ODR)。

    • 示例:

      1
      2
      3
      4
      5
      6
      7
      // myclass.h
      class MyClass {
      public:
      int getValue() { return value; } // 隐式内联
      private:
      int value = 0;
      };
      • getValue 的定义在类体内,自动视为 inline,可以在头文件中安全使用,多个 .cpp 文件包含时不会导致多重定义错误。
  • **显式 inline**:

    • 如果成员函数在类内仅声明,在类外定义,则需要显式使用 inline 关键字来指定内联行为,否则它将是普通函数(非内联)。

    • 示例:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      // myclass.h
      class MyClass {
      public:
      int getValue(); // 仅声明
      private:
      int value = 0;
      };

      inline int MyClass::getValue() { return value; } // 显式内联
      • 在类外定义的 getValue 使用 inline,确保它可以在头文件中定义,且允许多个翻译单元使用。
  • 效果

    • 无论是隐式还是显式内联,编译器可能将函数体直接插入调用点,减少调用开销。
    • 链接器会处理多份定义,确保符合 ODR。

2. 类内 inline 函数的实际作用

类内 inline 函数的作用与普通 inline 函数一致,主要包括:

  • 性能优化

    • 适合小型、频繁调用的成员函数(如 getter/setter、状态检查)。

    • 在嵌入式系统中,内联可以减少函数调用开销,优化实时性能。例如,在 FreeRTOS 中,检查任务状态的函数可以定义为内联:

      1
      2
      3
      4
      5
      6
      class TaskManager {
      public:
      bool isTaskRunning() { return taskState == RUNNING; } // 隐式内联
      private:
      TaskState taskState;
      };
  • 允许多定义

    • 类定义通常放在头文件中,隐式或显式内联的成员函数允许在多个 .cpp 文件中包含头文件,而不会导致链接错误。

    • 示例:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      // task.h
      class Task {
      public:
      void incrementCounter() { counter++; } // 隐式内联
      private:
      int counter = 0;
      };

      // main.cpp
      #include "task.h"
      void setup() { Task t; t.incrementCounter(); }

      // other.cpp
      #include "task.h"
      void loop() { Task t; t.incrementCounter(); }
      • incrementCounter 是隐式内联,多个源文件包含 task.h 不会报错。

接下来是inline函数的使用注意事项

  • 不能存在任何形式的循环语句
  • 不能存在过多的条件判断语句
  • 函数体不能过于庞大
  • 内联函数声明必须存在于调用语句之前