C/C++ 函数重载

        函数多态是C++在C语言的基础新增的功能。默认参数能够使用不同数目的参数调用同一个函数,而函数多态(函数重载)让您能够使用多个同名的函数。术语“多态”指的是有多种形式,因此函数多态允许函数可以有多种形式。类似地,术语“函数重载”指的是可以有多个同名的函数,因此对名称进行了重载。这两个术语指的是同一回事,但我们通常使用函数重载。可以通过函数重载来设计一系列函数一它们完成相同的工作,但使用不同的参数列表。

        重载函数就像是有多种含义的动词。例如,Piggy 小姐可以在棒球场为家乡球队助威(root),也可以在地里种植(root)菌类作物。根据上下文可以知道在每一种情况下root的含义是什么。同样,C++使用上下文来确定要使用的重载函数版本。

        函数重载的关键是函数的参数列表一也称为函数特征标(function signature)。如果两个函数的参数数目和类型相同,同时参数的排列顺序也相同,则它们的特征标相同,而变量名是无关紧要的。C++允许定义名称相同的函数,条件是它们的特征标不同。如果参数数目和/或参数类型不同,则特征标也不同。例如,可以定文一组原型如下的print()函数

        void print(const char *str, int width);    // #1
        void print(double d, int width);        // #2
        void print(long l, int width);            // #3
        void print(int i; int width);            // #4
        void print(const char * str);            // #5

        使用 print()函数时,编译器将根据所采取的用法使用有相应特征标的原型:
        print("Pancakes", 15);        // 使用 #1
        print("Syrup");                // 使用 #5
        print(1999, 10);            // 使用 #2
        print(1999L,12)            // 使用 #4
        print(1999l,15);            // 使用 #3

        例如,print(“Pancakes”, 15)使用一个字符串和一个整数作为参数,这与原型匹配使用被重载的函数时,需要在函数调用中使用正确的参数类型。例如,对于下面的语句:

        unsigned int year = 3210;
        print(year,6);            // 调用时存在二义性

        print()调用与那个原型匹配呢?它不与任何原型匹配!没有匹配的原型并不会自动停止使用其中的某个函数,因为C++将尝试使用标准类型转换强制进行匹配。如果#2原型是print()唯一的原型,则函数调用print(year, 6)将把year转换为double类型。但在上面的代码中,有3个将数字作为第一个参数的原型,因此有3种转换year的方式。在这种情况下,C++将拒绝这种函数调用,并将其视为错误。


        一些看起来彼此不同的特征标是不能共存的。例如,请看下面的两个原型:

        double cube(double x);
        double cube(double& x);

        您可能认为可以在此处使用函数重载,因为它们的特征标看起来不同。然而,请从编译器的角度来考虑这个问题。假设有下面这样的代码:

        cout << cube(x);
        
        参数X与double x原型和double &x原型都匹配, 因此编译器无法确定究竞应使用哪个原型。为避免这种混乱,编译器在检查函数特征标时,将把类型引用和类型本身视为同一个特征标。

        匹配函数时,并不区分const和非cost变量。请看下面的原型:

        void dribble(char * bits);            // 重载函数
        void dribble(const char *cbits);    // 重载函数
        void dabble(char *bits):            // 非重载函数
        void drivel(const char *bitsl);        // 非重载函数


        下面列出了各种函数调用对应的原型:

        const char p1[20) = "How's the weather?";
        char p2[20] = "How'sbusiness?“;
        dribbre(pl);        //调用dribble(const char *);
        dribbIe(p2);        //调用dribble(Char *)

        dabble(p1);        //no match
        dabble(p2);        // dabble(char *)

        drive(p1);        // drivel(const char *);
        drivel(p2);        // drivel(const char *);
        dribble()函数有两个原型,一个用于const指针, 另一个用于常规指针,编译器将根据实参是否为const来决定使用哪个原型。dribble()函数只与带非const参数的调用匹配,而drivel()函数可以与带const或非const参数的调用匹配。drivel()和 dabble()之所以在行为上有这种差别, 主要是由于将非const 值赋给cost变量是合法的,但反之则是非法的。


        请记住,是特征标,而不是函数类型使得可以对函数进行重载。例如,下面的两个声明是互斥的:
        
        long gronk(int n, float m); 
        double gronk(int n, froat m);
        
        因此C++不允许以这种方式重载gronk()。返回类型可以不同,但特征标也必须不同:

        long gronk(int n,float m);
        double gronk(float n,float m);


重载引用参数
        类设计和STL经常使用引用参数,因此知道不同引用类型的重载很有用。请春下面三个原型:

        void sink(double & rl);
        void sank(const double & r2);
        void sunk(double && r3);

        左值引用参数rl与可修改的左值参数(如 double变量)匹配;const 左值引用参数r2与可修改的左值参数、const左值参数和右值参数(如两个double值的和)匹配;
最后,左值引用参数r3与左值匹配。注意到与r1或r3匹配的参数都与r2 匹配。这就带来了一个问题,如果重载使用这三种参数的函数,结果将如何?答案是将调用最匹配的版本:

        void staff(double & rs) ;
        voit staff(const double & rcs);
        void stove(double & r1);
        void stove(const double & r2);
        void stove(double && r3];

        这让您能够根据参数是左值、const 还是右值来定制函数的行为:

        double x= 55.5;
        const double y = 32.0;
        stove(x);     //调用 stove (double &)
        stove(y);    //调用 stove (const double &)
        stove(x+y); //调用 stove (double &)

        如果没有定义函数 stove double &&), stove(x+y)将调用函数stove(const double &)。

示例源码:

// Len2024_0101.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
using namespace std;

unsigned long left(unsigned long num, unsigned ct);
char* left(const char * str, int n = 1);

int main()
{
	char trip[] = "Hawaii!!";
	unsigned long n = 12345678;
	int i;
	char * temp;
	for (i = 1; i < 10; i++)
	{
		cout << left(n, i) << endl;
		temp = left(trip, i);
		cout << temp << endl;
		delete[] temp;
	}
	return 0;
}
unsigned long left(unsigned long num, unsigned ct)
{
	unsigned digits = 1;
	unsigned long n = num;
	if (ct == 0 || num == 0)
	{
		return 0;
	}

	while (n /= 10)
	{
		digits++;
	}

	if (digits > ct)
	{
		ct = digits - ct;
		while (ct--)
		{
			num /= 10;
		}
		return num;
	}
	else
		return num;

}
char* left(const char * str, int n)
{
	if (n < 0)
	{
		n = 0;
	}
	char* p = new char[n + 1];
	int i;
	for (i = 0; i < n && str[i]; i++)
	{
		p[i] = str[i];
	}
	while (i <= n)
	{
		p[i++] = '\0';
	}
	return p;
}

执行结果:

        前面创建了一个left()函数,它返回一个指针,指向字符串的前 n个字符。下面添加另-个left()函数,它返回整数的前n位。例如,可以使用该函数来查看被存储为整数的、美国邮政编码的前3位一如果要根据城区分拣邮件,则这种操作很有用。

        该函数的整数版本编写起来比字符串版本更困难些,因为并不是整数的每一位被存储在相应的数组元素中。一种方法是,先计算数字含多少位。将数字除以10便可以去掉一位因此可以使用除法来计算数位。更准确地说,可以用下面的循环完成这种工作:

        ungigned digits = 1;
        while(n/=10)
            digits++;

        上述循环计算每次删除n中的一位时,需要多少次才能删除所有的位。前面讲过 n/=10是 n=n/10的缩写。例如,如果n为8,则该测试条将8/10的值(0,由于这是整数除法)赋给n。这将结束循环, digits的值仍然为1。但如果n为238,第一轮循环测试将n设置为238/10即23。这个值不为零,因此循环将digits增加到2。下一轮循环将n设置为23/10,即2。这个值还是不为零,因此digits将增加到3下一
        轮循环将n设置为2/10,即0,从而结束循环而,digits被设置为正确的值——3。

        现在假设知道数字共有5位,并要返回前3位,则将这个数除以10 后再除以10,便可以得到所需的值。每除以 10 次就删除数字的最后一位。要知道需要除多少位,只需将总位数减去要获得的位数即可。例如,要获得9位数的前4位,需要删除后面的5位。可以这样编写代码:

        ct =digits - ct;
        while(t--)
            num/=10;
        return num;
        
        上面程序将代码放到了一个新的left()函数中。该函数还包含一些用于处理特殊情况的代码,如用户要求显示0位或要求显示的位数多于总位数。由于新left()的特征标不同于旧的 left(),因此可以在个程序中使用这两个函数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/283207.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【时钟】分布式时钟HLC|Logical Time|Vector Clock|True Time

目录 简略 详细 附录 1 分布式系统不能使用NTP的原因 简略 分布式系统中不同于单机系统不能使用NTP(网络时间协议&#xff08;Network Time Protocol&#xff09;)来获取时间&#xff0c;所以我们需要一个特别的方式来获取分布式系统中的时间&#xff0c;mvcc也是使用time保证读…

2024最全面且有知识深度的web3开发工具、web3学习项目资源平台

在Web3技术迅速发展的时代&#xff0c;寻找一个综合且深入的Web3开发工具和学习项目资源平台变得至关重要。今天&#xff0c;我将向大家介绍一个非常有价值的网站&#xff0c;它就是https://web3x.world 。 Web3X是一个全面而深入的Web3开发者社区&#xff0c;为开发者们提供了…

最优化方法Python计算:无约束优化应用——神经网络回归模型

人类大脑有数百亿个相互连接的神经元&#xff08;如下图(a)所示&#xff09;&#xff0c;这些神经元通过树突从其他神经元接收信息&#xff0c;在细胞体内综合、并变换信息&#xff0c;通过轴突上的突触向其他神经元传递信息。我们在博文《最优化方法Python计算&#xff1a;无约…

跳跃表原理及实现

一、跳表数据结构 跳表是有序表的一种&#xff0c;其底层是通过链表实现的。链表的特点是插入删除效率高&#xff0c;但是查找节点效率很低&#xff0c;最坏的时间复杂度是O(N)&#xff0c;那么跳表就是解决这一痛点而生的。 为了提高查询效率&#xff0c;我们可以给链表加上索…

打破成本壁垒,免费SSL证书为中小企业保驾护航

HTTPS&#xff0c;这个曾经看似遥远的技术词汇&#xff0c;如今已与我们每个人的网络生活息息相关。而实现HTTPS加密传输的关键一环——SSL证书&#xff0c;正以其独特的安全性能&#xff0c;为网站筑起一道坚实的防护墙。更令人惊喜的是&#xff0c;免费SSL证书服务已经到来&a…

数据结构与算法教程,数据结构C语言版教程!(第二部分、线性表详解:数据结构线性表10分钟入门)三

第二部分、线性表详解&#xff1a;数据结构线性表10分钟入门 线性表&#xff0c;数据结构中最简单的一种存储结构&#xff0c;专门用于存储逻辑关系为"一对一"的数据。 线性表&#xff0c;基于数据在实际物理空间中的存储状态&#xff0c;又可细分为顺序表&#xff…

自动化网络故障修复管理

什么是故障管理 故障管理是网络管理的组成部分&#xff0c;涉及检测、隔离和解决问题。如果实施得当&#xff0c;网络故障管理可以使连接、应用程序和服务保持在最佳水平&#xff0c;提供容错能力并最大限度地减少停机时间。专门为此目的设计的平台或工具称为故障管理系统。 …

JavaScript setTimeout和setInterval的用法与区别详解

目录 I. 总述 II. setTimeout()函数 III. setInterval()函数 IV. 新年倒计时案例 Javascript的setTimeOut和setInterval函数应用非常广泛&#xff0c;它们都用来处理延时和定时任务&#xff0c;下面这篇文章主要给大家介绍了关于JavaScript setTimeout和setInterval的用法与…

解决 Nginx 反向代理中的 DNS 解析问题:从挑战到突破20231228

引言 在使用 Nginx 作为反向代理服务器时&#xff0c;我们可能会遇到各种配置和网络问题。最近&#xff0c;我遇到了一个有趣的挑战&#xff1a;Nginx 在反向代理配置中无法解析特定的域名&#xff0c;导致 502 错误。这个问题的解决过程不仅揭示了 Nginx 的一个不太为人知的功…

分布式【雪花算法】

雪花算法 背景&#xff1a;在分布式系统中&#xff0c;需要使用全局唯一ID&#xff0c;期待ID能够按照时间有序生成。 **原理&#xff1a;**雪花算法是 64 位 的二进制&#xff0c;一共包含了四部分&#xff1a; 1位是符号位&#xff0c;也就是最高位&#xff0c;始终是0&am…

MySQL存储过程、创建、调用、查看、删除、存储过程与函数的额区别、缺陷等、存储过程写分页等

MySQL存储过程 1、存储过程的定义2、存储过程使用的意义3、存储过程的创建4、存储过程的调用5、存储过程的查看6、存储过程的删除7、存储及过程与函数的区别8、存储过程的缺陷9、存储过程写分页 1、存储过程的定义 存储过程&#xff1a;存储过程&#xff08;Stored Procedure&…

redis 从0到1完整学习 (十二):RedisObject 之 List 类型

文章目录 1. 引言2. redis 源码下载3. redisObject 管理 List 类型的数据结构3.1 redisObject 管理 List 类型3.2 List PUSH 源码 4. 参考 1. 引言 前情提要&#xff1a; 《redis 从0到1完整学习 &#xff08;一&#xff09;&#xff1a;安装&初识 redis》 《redis 从0到1…

pytest --collectonly 收集测试案例

pytest --collectonly 是一条命令行指令&#xff0c;用于在运行 pytest 测试时仅收集测试项而不执行它们。它会显示出所有可用的测试项列表&#xff0c;包括测试模块、测试类和测试函数&#xff0c;但不会执行任何实际的测试代码。 这个命令对于查看项目中的测试结构和确保所有…

千里马2023年终总结-android framework实战

背景&#xff1a; hi粉丝朋友们&#xff1a; 2023年马上就过去了&#xff0c;很多学员朋友也都希望马哥这边写个年终总结&#xff0c;因为这几个月时间都忙于新课程halsystracesurfaceflinger专题的开发&#xff0c;差点都忘记了这个事情了&#xff0c;今天特别花时间来写个bl…

思维链COT原理探究

要进行因果分析&#xff0c;需要把思维链中的不同元素拆解开来&#xff0c;然后通过控制变量实验&#xff0c;来研究不同元素对COT效果的影响。以下两篇论文的核心差异就在于: COT的变量拆解&#xff0c;以及控制变量的实验方式。 结合两篇论文的实验结论&#xff0c;可能导致…

【深度学习:Convolutional Neural Networks】卷积神经网络入门指南

卷积神经网络&#xff08;CNN&#xff09;是深度学习领域最引人注目的成就之一。自从LeCun等人在20世纪90年代初引入以来&#xff0c;CNN在图像处理、视频分析和自然语言处理等领域取得了显著的成就。在这篇博客中&#xff0c;我们将探讨CNN的基本原理、结构和一些实际应用案例…

实验3 vTPM相关

一、实验目的 1.了解vTPM原理和相关知识&#xff1b;2.创建具备vTPM的虚拟机&#xff1b;3.加深对可信计算技术的理解。 二、实验内容 安装seabios&#xff0c;libtpms&#xff0c;swtpm&#xff0c;qemu‐tpm&#xff1b;启动vTPM&#xff1b;安装虚拟机。 三、实验环境 …

2013年第二届数学建模国际赛小美赛B题寄居蟹进化出人类的就业模式解题全过程文档及程序

2013年第二届数学建模国际赛小美赛 B题 寄居蟹进化出人类的就业模式 原题再现&#xff1a; 寄居蟹是美国最受欢迎的宠物品种&#xff0c;依靠其他动物的壳来保护。剥去寄居蟹的壳&#xff0c;你会看到它柔软、粉红色的腹部卷曲在头状的蕨类叶子后面。大多数寄居蟹喜欢蜗牛壳&…

Unity Window安装包制作

Unity Window安装包制作 介绍一、RAR自解压方式1、找到Unity打包的可执行程序2.创建自解压文件3.配置设置4、最后点击确定等待压缩完成即可&#xff08;默认生成位置为你选中文件右键点击添加到压缩文件时的路径&#xff09; 二、Setup Factory工具安装制作Window安装包相关常用…

2023年成都市中等职业学校学生技能大赛“网络搭建及应用”赛项竞赛样卷

2023年成都市中等职业学校学生技能大赛 “网络搭建及应用”赛项竞赛样卷 &#xff08;总分1000分&#xff09; 目录 2023年成都市中等职业学校学生技能大赛 “网络搭建及应用”赛项竞赛样卷 网络建设与调试项目&#xff08;500分&#xff09; 服务器搭建与运维项目&#xff08;…