【类定义系列三】内联函数进阶

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

类的内联成员函数必须在头文件中实现吗

类的内联成员函数类外实现时,inline写几次,规则是什么

是声明或者实现两者只允许某一个写一次,还是实现必须写,声明可写可不写


一、类的内联成员函数必须在头文件中实现吗?

结论:工程实践中「必须」,语法上仅极端特例可例外(几乎无实用价值)

核心原因(结合类的复用特性):

类的定义本身几乎都放在头文件中(因为多个 .cpp 文件需要包含类定义来创建对象、调用成员函数),而内联函数的核心要求是:编译器在每个调用该函数的编译单元(.cpp)中,必须看到函数的完整定义(否则无法完成"调用替换为函数体"的内联优化,甚至会触发链接错误)。

经测试,在源文件中写调用就会报链接错误。

具体分析:

  1. 正常场景(类对外复用)

    若类的内联成员函数(无论类内/类外实现)不在头文件,仅放在某个 .cpp 中:

    • 其他 .cpp 包含类头文件时,只能看到成员函数的声明,看不到定义 → 编译器无法内联,退化为普通函数调用;
    • 更严重的是,内联函数的链接属性是 internal(仅当前编译单元可见),其他 .cpp 调用时会报"未定义的引用"链接错误(因为找不到函数定义)。
      因此这种场景下,类的内联成员函数必须在头文件中实现(类内实现直接写在头文件的类定义里,类外实现也需写在头文件的类定义下方)。
  2. 极端特例(无实用价值)

    若类是「单个 .cpp 内的局部类」(仅该文件定义、使用,不对外暴露),则其内联成员函数可在该 .cpp 中实现。但这种场景极少(类的核心价值是复用,局部类无复用意义),示例如下:

    cpp 复制代码
    // test.cpp(仅本文件使用的局部类)
    #include <iostream>
    using namespace std;
    
    // 局部类:仅在test.cpp中可见
    class LocalClass {
    public:
        // 内联成员函数:仅本文件实现和调用
        inline void print() {
            cout << "局部类的内联函数" << endl;
        }
    };
    
    int main() {
        LocalClass lc;
        lc.print(); // 正常内联,无问题
        return 0;
    }

二、类外实现内联成员函数时,inline 写几次?规则是什么?

核心规则(一句话总结):

inline 必须写在类外实现处;类内声明处可写、可不写(不影响合法性),但绝对不能"只在声明处写、实现处不写"。

详细规则与场景拆解:
声明处 实现处 合法性 说明
不写 inline inline ✅ 推荐 内联是"实现属性",仅在实现处标记更清晰,符合C++设计习惯
inline inline ✅ 合法 无问题,但属于冗余写法(不推荐)
inline 不写 inline ❌ 非法 编译器会将函数视为普通函数,多个编译单元包含头文件时会报"多重定义"错误
不写 inline 不写 inline ❌ 非内联❌ 非法 函数失去内联属性,退化为普通成员函数
示例验证(头文件中实现):
cpp 复制代码
// Person.h(正确写法)
#ifndef PERSON_H
#define PERSON_H
#include <string>
using namespace std;

class Person {
private:
    string name;
public:
    // 场景1:声明处不写inline,实现处写(推荐)
    void setName(const string& n); 

    // 场景2:声明处写inline,实现处也写(合法但冗余)
    inline string getName(); 
};

// 实现处必须加inline(核心!)
inline void Person::setName(const string& n) {
    name = n;
}

inline string Person::getName() {
    return name;
}

#endif
反例(错误写法):
cpp 复制代码
// Person.h(错误写法:声明写inline,实现不写)
class Person {
public:
    inline void setName(const string& n); // 声明加inline
};

// 实现处未加inline → 非法!
void Person::setName(const string& n) { 
    name = n;
}

// 编译结果:多个.cpp包含该头文件时,报"multiple definition of Person::setName"
关键总结
  1. 类的内联成员函数(对外复用场景)必须在头文件实现,否则无法内联且会触发链接错误;
  2. 类外实现内联成员函数时:
    • inline 「必须」出现在实现处;
    • 声明处可写可不写(推荐不写,更符合语义);
    • 绝对禁止"声明写、实现不写"(会导致多重定义错误);
  3. 类内实现的成员函数默认内联,无需显式加 inline(本质是编译器自动将类内实现标记为inline)。

总结

针对上面的反例,声明写inline,实现不写测试发现并未报错

AI回答是编译器优化

但是我隐约记得以前看黑马教程的时候就说过声明或者实现有一个地方写了就行,暂时先这样,工作就按照最规范的写法准没问题

下面一篇文章再来纠结具体为什么不报错

相关推荐
北京流年2 小时前
执行clang --version报错说由于找不到 libgcc_s_seh-1.dll和 找不到 libstdc++-6.dll 这两个文件
开发语言·c++
weixin_440730502 小时前
Java基础学习day01
java·开发语言·学习
军军君013 小时前
Three.js基础功能学习一:环境资源及基础知识
开发语言·javascript·学习·3d·前端框架·threejs·三维
是垚不是土3 小时前
基于DDNS-Go动态域名解析配置:实现多网络线路冗余切换方案
运维·开发语言·网络·阿里云·golang·运维开发
@大迁世界3 小时前
JavaScript 框架的终结
开发语言·前端·javascript·ecmascript
catchadmin3 小时前
PHP True Async 最近进展以及背后的争议
开发语言·php
fpcc3 小时前
跟我学C++中级篇—Linux内核中链表分析
linux·c++·链表
PPPPickup3 小时前
easychat项目复盘---管理端系统设置
java·开发语言·前端
挖矿大亨3 小时前
C++中的this指针
java·开发语言·c++