1.函数重载的原理
名称修饰(Name Mangling)
- 作用:编译器在编译时对函数名进行编码,生成唯一的内部标识符,使得同名函数能通过参数列表的差异被区分。
- 示例:
void func(int a); // 修饰后可能为 _Z4funci
void func(double b); // 修饰后可能为 _Z4funcd
void func(int a, int b); // 修饰后可能为 _Z4funcii
- 编码规则(编译器实现相关):
- 参数类型会被编码(如
i
代表int
,d
代表double
)。 - 函数名前缀可能包含作用域信息(如类名、命名空间)。
- 不同编译器(如GCC、MSVC)的编码方式可能不同,但逻辑一致。
- 参数类型会被编码(如
2. 函数重载的判断依据
- 参数列表的差异:
- 参数类型不同(如
int
vsdouble
)。 - 参数数量不同(如
func(int)
vsfunc(int, int)
)。 - 参数顺序不同(如
func(int, double)
vsfunc(double, int)
)。
- 参数类型不同(如
- 返回值不影响重载:
- 仅返回值不同无法构成重载(如
int func()
和double func()
会报错)。
- 仅返回值不同无法构成重载(如
- const/volatile 限定符的影响:
- 参数中的
const
可能影响重载(如func(const int&)
和func(int&)
视为不同)。 - 函数返回值或函数本身的
const
属性不影响重载。
- 参数中的
3. 底层实现流程
- 编译阶段:
- 编译器为每个重载函数生成唯一的修饰名。
- 检查参数列表是否满足重载条件(如类型、数量、顺序)。
- 链接阶段:
- 链接器根据修饰名匹配函数调用,确保调用正确的函数实现。
4. 与C语言的区别
- C语言不支持重载:
- C编译器不进行名称修饰,直接使用原始函数名(如
func
)。 - 同名函数会导致链接错误(
multiple definition
)。
- C编译器不进行名称修饰,直接使用原始函数名(如
- C++的兼容性:
- 使用
extern "C"
可禁用名称修饰,使C++代码与C兼容:extern "C" void func(int); // 保持C风格的函数名
- 使用
2.const的核心机制
编译器层面的检查(核心机制)
const
的主要作用是编译期约束,编译器会:
- 拒绝所有直接修改
const
变量的代码(如*s = 'H'
) - 通过类型系统阻止隐式类型转换(如
const char*
→char*
)
运行阶段,真正起到保护的是操作系统对于权限的检查,字符串常量是被硬编码到只读常量节的。
- 操作系统内存分页机制:
- 现代操作系统通过MMU(内存管理单元)将物理内存划分为固定大小的页(通常4KB)
- 每个页表项(Page Table Entry)包含权限标志位(读/写/执行)
- 字符串常量所在的
.rodata
段会被标记为只读(Read-Only)
- 硬件级保护:
- 当CPU执行
*s = 'H'
这样的写操作时:- MMU检查目标页面的权限
- 发现页面标记为只读
- 触发页错误(Page Fault)
- 操作系统捕获页错误后:
- 如果是合法操作(如动态加载库),可能触发写时复制(Copy-On-Write)
- 如果是非法操作(修改只读内存),则发送段错误信号(SIGSEGV)
- 当CPU执行