IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 从几个例子看函数重载 -> 正文阅读

[C++知识库]从几个例子看函数重载

常用的几类函数

#include <iostream>
 
 void func(int a){
     std::cout << "global func: " << a << std::endl;
 }
 namespace test{
     void func(int a){ 
         std::cout << "namespace test func: " << a << std::endl;
     }   
 };
 
 class Demo {
     public:
     void func(int a){
         i = 1;
         std::cout << "class member func: " << a << std::endl;
     }   
     int i{0};
 };
 
 int main()
 {
     func(1);
     test::func(1);
     Demo d;
     d.func(1);
     return 0;
 }

函数的重载

对于程序的整个生命周期如下:编写程序(源代码)-> 预处理 -> 编译(扫描->词法分析->语法分析->语义分析->源代码优化->代码生成->目标代码优化) -> 汇编 -> 链接 -> 运行;
编译器将源代码编译产生目标文件时,符号名与相应的变量和函数进行对应,在比较早的时候,两者是一样的,比如汇编源代码中包含一个函数foo,编译成目标文件时,对应的符号名也是foo;C语言的规则比较类似,将全局变量和函数的符号名前加上下划线"_";
比如:

 extern "C" {
 void func(int a){ 
     std::cout << "global func: " << a << std::endl;
 }
 }

编译成的符号如下(readelf -s main | grep func):

Num: Value Size Type Bind Vis Ndx Name
60: 00000000000011e9 74 FUNC GLOBAL DEFAULT 16 func

由于C语言的符号生成规则如此,所以不支持函数的重载。也因此只要符号相同(相同的函数名、变量名会编译失败)

那么对于C++,它拥有类、继承、虚机制、重载、名称空间等这些特性,使符号管理(符号生成规则)更为复杂。为了支持这些特性,发明了Name Decoration 或 Name Mangling机制

看如下函数的符号是如何:

 int func(int){return 0;};
 float func(float){return 0;};
 class C{
     public:
     int func(int){return 0;};  
     class C2 {
         public:
         int func(int){return 0;};
     };  
 };
 namespace N{
 int func(int){return 0;};
 class C{
     public:
     int func(int){return 0;};  
 };
 };
 int main(){
     func(1);
     func(1.0f);
     C c;
     c.func(1);
     C::C2 c2;
     c2.func(1);
     
     N::func(1);
     N::C c1; 
     c1.func(1);
     
     return 0;
 }

命令:
编译: g++ main.cpp -o main
查看符号:readelf -s main | grep func

统计:

函数签名修饰后名称(符号名)
int func(int)_Z4funci
float func(float)_Z4funcf
int C::func(int)_ZN1C4funcEi
int C::C2::func(int)_ZN1C2C24funcEi
int N::func(int)_ZN1N4funcEi
int N::C::func(int)_ZN1N1C4funcE

基本规则如下:

所有符号以_Z开头,对于嵌套的名字(名称空间或类里面),后面紧跟着“N”, 然后是各个名称空间和类的名字,每个名字前是名字字符串长度,再以E结尾,对于函数来说,它的参数列表紧跟在“E”后面,对于int类型来说,就是字母i。

  <type> ::= <builtin-type>
         ::= <qualified-type>
         ::= <function-type>
         ::= <class-enum-type>
         ::= <array-type>
         ::= <pointer-to-member-type>
         ::= <template-param>
         ::= <template-template-param> <template-args>
         ::= <decltype>
         ::= P <type>        # pointer
         ::= R <type>        # l-value reference
         ::= O <type>        # r-value reference (C++11)
         ::= C <type>        # complex pair (C99)
         ::= G <type>        # imaginary (C99)
         ::= <substitution>  # See Compression below

<CV-qualifiers>      ::= [r] [V] [K] 	  # restrict (C99), volatile, const

<builtin-type>   ::= v	# void
				 ::= w	# wchar_t
				 ::= b	# bool
				 ::= c	# char
				 ::= a	# signed char
				 ::= h	# unsigned char
				 ::= s	# short
				 ::= t	# unsigned short
				 ::= i	# int
				 ::= j	# unsigned int
				 ::= l	# long
				 ::= m	# unsigned long
				 ::= x	# long long, __int64
				 ::= y	# unsigned long long, __int64
				 ::= n	# __int128
				 ::= o	# unsigned __int128
				 ::= f	# float
				 ::= d	# double
				 ::= e	# long double, __float80
				 ::= g	# __float128
				 ::= z	# ellipsis
                 ::= Dd # IEEE 754r decimal floating point (64 bits)
                 ::= De # IEEE 754r decimal floating point (128 bits)
                 ::= Df # IEEE 754r decimal floating point (32 bits)
                 ::= Dh # IEEE 754r half-precision floating point (16 bits)
                 ::= DF <number> _ # ISO/IEC TS 18661 binary floating point type _FloatN (N bits)
                 ::= DB <number> _        # C23 signed _BitInt(N)
                 ::= DB <instantiation-dependent expression> _ # C23 signed _BitInt(N)
                 ::= DU <number> _        # C23 unsigned _BitInt(N)
                 ::= DU <instantiation-dependent expression> _ # C23 unsigned _BitInt(N)
                 ::= Di # char32_t
                 ::= Ds # char16_t
                 ::= Du # char8_t
                 ::= Da # auto
                 ::= Dc # decltype(auto)
                 ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
				 ::= u <source-name> [<template-args>] # vendor extended type

函数的名称修饰是否包含返回值,有如下解释:
Whether the mangling of a function type includes the return type depends on the context and the nature of the function. The rules for deciding whether the return type is included are:

  1. Template functions (names or types) have return types encoded, with the exceptions listed below.
  2. Function types not appearing as part of a function name mangling, e.g. parameters, pointer types, etc., have return type encoded, with the exceptions listed below.
  3. Non-template function names do not have return types encoded.

The exceptions mentioned in (1) and (2) above, for which the return type is never included, are

  1. Constructors.
  2. Destructors.
  3. Conversion operator functions, e.g. operator int.

const重载

先看下面几个例子:
1:

 void func(int a){ 
     std::cout << "global func: " << a << std::endl;
 }
 void func(const int a){
     std::cout << "global func: " << a << std::endl;
 }

和2:

 void func(int& a){ 
     std::cout << "global func: " << a << std::endl;
 }
 void func(const int& a){ 
     std::cout << "global func: " << a << std::endl;
 }

先猜测下上述两个例子表现如何?
结论:例1编译失败,例2编译成功;为什么呢?
从编译出的符号进行倒推:

函数原型符号
void func(int)_Z4funci
void func(const int)_Z4funci
void func(int&)_Z4funcRi
void func(const int&)_Z4funcRKi

由于void func(int) 和void func(const int) 生成的符号相同,那么必然会编译失败;其思想在于,当函数参数是基本的value时,都是将实参拷贝一份然后传入函数,那么const与否是不会影响到调用方,所以无需区分这两种情况(编译器规则)。

再看一个例子:

 class Demo {
     public:
     void func(int a){ 
         i = 1;
         std::cout << "class member func: " << a << std::endl;
     }   
     void func(int a) const {
     	 // i = 1; // compile fail 
         std::cout << "class member const func: " << a << std::endl;
     }   
     int i{0};
 };

编译ok;

函数原型符号
void const Demo::func(int)_ZNK4Demo4funcEi
void Demo::func(int)_ZN4Demo4funcEi

第二个成员函数的const是修饰Demo object的。

const修饰返回值时,由于“Non-template function names do not have return types encoded”;对于这种情况,返回值使用和不使用const修饰生成的符号是相同的,若同时存在则会编译失败。StackOverflow 解答

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-02-07 13:32:31  更:2022-02-07 13:34:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:44:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码