《C++初阶之类和对象》【命名空间 + 输入输出 + 缺省参数 + 函数重载】

【命名空间 + 输入&输出 + 缺省参数 + 函数重载】目录

  • 前言:
  • ---------------hello world---------------
    • 比较C语言和C++的第一个程序:hello word
  • ---------------命名空间---------------
    • 什么是命名空间?
    • 怎么使用命名空间?
      • 怎么定义命名空间?
      • 怎么访问命名空间?
    • C++为什么要引入命名空间?
    • 命名空间怎么就解决了同名标识符互相干扰的难题?
      • 命名冲突的本质是什么?
      • C++的作用域的访问顺序是什么?
    • 命名空间中可以放什么?
    • 命名空间怎么进行嵌套使用?
    • 命名空间的其他注意事项
  • ---------------输入&输出---------------
    • C++的输入&输出是什么?
    • C++的cin和cout相较于C语言的输入和输出有什么优势?
    • 关于cin和cout还有哪些需要注意事情?
  • ---------------缺省参数---------------
    • 什么是缺省参数?
    • 缺省参数的有哪几种?
    • 使用缺省参数时的注意事项有哪些?
    • C++中引入缺省参数有什么好处?
  • ---------------函数重载---------------
    • 什么是函数重载?
    • 满足函数重载的条件有哪些?
    • 还有哪些特殊的函数重载?
    • 函数重载和缺省参数有什么不同?

在这里插入图片描述

往期《C++初阶》回顾:

/------------ 入门基础 ------------/
【C++的前世今生】

前言:

(。・ω・。)ノ♡hi~ 亲爱的小伙伴们!(≧∇≦)ノ 当芒种的风✨呼呼吹过,田间地头满是农人播种希望的身影,今天我们也迎来了正式学习 C++ 知识的新旅程了(★ω★)
那么,就让我们像芒种时节播撒种子一样,播撒 C++ 这颗种子,期待未来收获满满的编程硕果 🍎✨

---------------hello world---------------

比较C语言和C++的第一个程序:hello word

/*------------使用C语言编写第一个 hello world 代码------------*/
#include <stdio.h>int main()
{printf("hello world");return 0;
}/*------------使用C++编写第一个 hello world 代码------------*/
#include <iostream>   //1.使用#include包含C++的库
using namespace std;  //2.使用命名空间int main()
{cout << "hello world" << endl;  //3.使用输出流对象cout向终端控制窗口(小黑窗口) 输出字符串return 0;
}

---------------命名空间---------------

什么是命名空间?

命名空间(Namespace):是一种将标识符(如:变量、函数、类等)组织成不同作用域,用于组织代码、避免命名冲突的机制

怎么使用命名空间?

使用命名空间整体上主要是分为两步:

第一步:定义命名空间

第二步:访问命名空间

怎么定义命名空间?

namespace 命名空间名称 
{// 可包含的内容:// - 变量// - 函数// - 类/结构体// - 其他命名空间类型 变量名;返回类型 函数名(参数列表) { /* 函数体 */ }class 类名 { /* 类定义 */ };struct 结构体名 { /* 结构体定义 */ };namespace 子命名空间名 { /* ... */ }
}

怎么访问命名空间?

在 C++ 中,命名空间(namespace)的使用方式非常灵活,以下是博主精心挑选的三个最实用的命名空间的使用方法,涵盖从基础到高级的所有场景:

  1. 直接通过作用域解析符 :: 访问
  2. 使用 using 声明(引入特定成员)
  3. 使用 using namespace 指令(引入整个空间)

1. 直接通过作用域解析符 :: 访问

  • 适用场景:精确控制访问路径,避免歧义。
/*----------------------------命名空间的使用----------------------------*/
#include <iostream>
#include <string>/*---------------第一步:命名空间的定义---------------*/
namespace my_space
{string str = "这是我定义的命名空间中的字符串";void fun(){cout << "这是我定义的命名空间中的函数";}
}int main()
{/*---------------第二步:演示如何使用自定义的命名空间中的成员---------------*//*-------------第一种的使用方法:使用作用域解析符访问-------------*/cout << my_space::str << endl;//printf("%s", my_space::str);  注意:这里你可别使用C语言的printf进行输出C++风格的字符串//string是C++的字符串对象,printf不能输出对象这种类型,(仔细回想一下C++中是没用字符串这种类型的,C语言是使用字符数组存储字符串的)printf("%s", my_space::str.c_str()); //如果你执意要使用printf进行输出的话,可以将string通过的函数c_str()转化为C风格的字符串return 0;
}

在这里插入图片描述

2. 使用 using 声明(引入特定成员)

  • 适用场景:需要频繁使用某个命名空间的少数成员
/*----------------------------命名空间的使用----------------------------*/#include <iostream>
#include <string>
using namespace std;/*---------------第一步:命名空间的定义---------------*/
namespace my_space
{string str = "这是我定义的命名空间中的字符串";void fun(){cout << "这是我定义的命名空间中的函数";}
}using  my_space::str;  // 注意:使用 using 声明(引入特定成员)必须写在自定义的命名空间的后面int main()
{/*---------------第二步:演示如何使用自定义的命名空间中的成员---------------*//*-------------第二种的使用方法:使用 using 声明(引入特定成员)-------------*/cout << str << endl;my_space::fun();return 0;
}

在这里插入图片描述

3. 使用 using namespace 指令(引入整个空间)

  • 适用场景:短代码片段或源文件中(头文件中禁止使用
/*----------------------------命名空间的使用----------------------------*/#include <iostream>
#include <string>
using namespace std;/*---------------第一步:命名空间的定义---------------*/
namespace my_space
{string str = "这是我定义的命名空间中的字符串";void fun(){cout << "这是我定义的命名空间中的函数";}
}using namespace my_space;  // 注意:使用 using namespace 指令(引入整个空间)必须写在自定义的命名空间的后面int main()
{/*---------------第二步:演示如何使用自定义的命名空间中的成员---------------*//*-------------第三种的使用方法:使用 using namespace 指令(引入整个空间)-------------*/cout << str << endl;fun();return 0;
}

在这里插入图片描述

看到这里我相信有不少的小伙伴们会想到这行代码:using namespace std;

这行代码官方的回答是:将 std 命名空间中的所有成员引入到当前作用域,允许直接使用这些标识符而无需添加 std:: 前缀

简单点说就是:我们使用namespace定义一个命名空间,就像是在全局作用域这片广袤的大地上面使用围墙围起来一片属于自己的土地,这片土地有了主人(命名空间的名字)

以后谁再想访问围墙里面的东西,必须得到这片土地的主人的同意(指定命名空间的名字进行访问)

其中有一片土地简直就是世外桃源,土地的主人名叫std,很多人想去哪里但是每次都要征得同意(添加 std:: 前缀),是不是很麻烦,因此我们使用using namespace std 的感觉就像是:偷了了std的家——暴力将这片土地上的围墙给拆除了(大型项目中不建议这么做,这将会导致命名空间失去意义),从此大家去世外桃源就是想去就去了!!!

C++为什么要引入命名空间?

当项目规模较大时,不同库或模块可能使用相同的名称 (尤其是当两名在同一个项目组的程序员合并他俩的代码的时候,合并之后往往他俩有可能就会打起来),可能会导致命名冲突。

小案例:我写的变量和库函数的函数名引发命名冲突

#include <iostream>
#include <stdlib.h>
/*------------任务:定义变量 + 在终端上打印该变量存储的值------------*/int rand = 100;
int main()
{printf("%d", rand); //error:“rand”: 重定义;以前的定义是“函数”return 0;
}

在这里插入图片描述

而为了让大家能和睦相处,因此C++ 引入了命名空间机制,它通过逻辑隔离的方式,确保不同作用域内的同名标识符不会互相干扰,从而让代码协作更加和谐高效。

小案例:使用命名空间避免命名冲突

#include <iostream>
#include <stdlib.h>
/*------------任务:定义变量 + 在终端上打印该变量存储的值------------*/namespace my_space
{int rand = 100;
}int main()
{printf("%d", rand); //error:“rand”: 重定义;以前的定义是“函数”return 0;
}

在这里插入图片描述

命名空间怎么就解决了同名标识符互相干扰的难题?

为了回答这个问题,我们要对 作用域 有一定的理解,那先从C语言说起吧:

关于C语言的作用域有哪些,不同的人会给出不同的划分种类,但是从本质上理解C语言就两个作用域:函数局部作用域全局作用域

因为一个C程序中所有的变量、函数存在的位置无非就是:函数局部作用域全局作用域

(其中函数只能存储于全局作用域中)


而这时候我们就要仔细思考:是C语言的哪些不足导致了上面的命名冲突的情况,而使得C++不得不引入命名空间

回答:由于C语言的作用域过于单一,当项目规模较大时,会有大量的变量、函数都存在于全局作用域中,这样的话就可能会导致很多命名冲突。

(在同一个函数作用域中一般我们不会使用相同的标识符进行命名)

所以C++的思路是:可不可以从全局作用域中再分出去一些域,所以就有了C++四大作用域:

  1. 函数局部作用域
  2. 命名空间作用域
  3. 类域
  4. 全局作用域

为解决这个问题,我们还要了解:

  • 命名冲突的本质是什么?
  • C++的作用域的访问顺序是什么?

命名冲突的本质是什么?

命名冲突(Name Conflict):在同一作用域内使用相同的标识符:变量名、函数名、类名等),导致编译器无法区分它们的情况。


注意:这里我们要抓住核心的的名词:“同一作用域 + 相同的标识符”

所以这也就好理解为什么:C++又在C语言的基础上又创建了两个作用域

C++的作用域的访问顺序是什么?

在 C++ 中,当访问一个标识符时,编译器会按照特定的顺序查找该标识符的定义,这个过程称为 名称查找(Name Lookup)

理解这个顺序对于避免命名冲突和理解代码行为至关重要。

名称查找顺序:

  1. 局部作用域(Block Scope):首先在当前函数的局部作用域中查找标识符,包括在当前块(如:if 语句、for 循环等)中定义的变量。
  2. 类作用域(Class Scope):如果在局部作用域中没有找到标识符,那么会在包含当前函数的类的成员作用域中查找。(如果当前函数是类的成员函数的话)
  3. 命名空间作用域(Namespace Scope):如果在类作用域中没有找到标识符,那么会在当前命名空间中查找。(如果定义的有命名空间的话)
  4. 全局作用域(Global Scope):如果在上面的作用域中都没有找到标识符,那么就会在全局作用域中查找。
  5. std 命名空间:在 C++ 中,std 是一个特殊的命名空间,包含了标准库的所有内容。如果在全局作用域中没有找到标识符,那么会检查 std 命名空间。

综上所述:这样做我们就是实现了:对标识符的名称进行本地化,以避免命名冲突或名字污染。也就是说:虽然咱俩写的标识符的名称相同,但是代码合并后重名的标识符不再是在同一个作用域:全局作用域 ,而是现在在不同的作用域:不同的 命名空间作用域,所以不构成命名冲突。

所以合并完代码之后咱俩还是好朋友🐶

命名空间中可以放什么?

/*------------C++的命名空间使用------------*/
#include <stdio.h>
#include <stdlib.h>/*------------定义一个的命名空间:my_utils------------*/
namespace my_utils
{//1.命名空间中可以定义:变量int rand = 100;  //定义变量(故意与标准库rand函数同名)//2.命名空间中可以定义:函数int add(int left, int right){return left + right;}//3.命名空间中可以定义:自定义数据类型struct SingleListNode{int data;struct SingleListNode* next;};
}
int main()
{//1.使用默认访问(全局命名空间访问):这里访问的是全局的标准库中rand函数地址printf("%p\n", rand);printf("%p\n", ::rand);//2.使用指定域(my_utils命名空间)访问:这里访问是my_utils命名空间的rand变量的值printf("%d\n", my_utils::rand);return 0;/* * 关键点说明:* 1. ::rand		 - 访问全局命名空间的rand(标准库函数)* 2. my_utils::rand - 访问my_utils命名空间的rand变量* 3. 实际开发中应避免与标准库同名*/
}

命名空间怎么进行嵌套使用?

/*------------命名空间的嵌套使用------------*/
#include <stdio.h>/*------------定义一个的命名空间:school------------*/
//1.外层命名空间:school
namespace school
{//2.内层命名空间1:teacher_anamespace teacher_a{//2.1:定义变量int rand = 50;//2.2:定义函数int add(int left, int right){return left + right;}}//2.内层命名空间2:teacher_bnamespace teacher_b{//2.1:定义变量int rand = 100;//2.2:定义函数int add(int left, int right){return (left + right) * 10; //将结果放大原来的10倍}}
}
int main()
{/*------------访问嵌套命名空间中的成员------------*/// 1. 访问不同命名空间中的同名变量printf("teacher_a的rand值: %d\n", school::teacher_a::rand);  // 输出50printf("teacher_b的rand值: %d\n", school::teacher_b::rand);  // 输出100// 2. 调用不同命名空间中的同名函数printf("teacher_a的加法结果(1+2): %d\n",school::teacher_a::add(1, 2));  // 输出3(1+2)printf("teacher_b的加法结果(1+2): %d\n",school::teacher_b::add(1, 2));  // 输出30((1+2)*10)return 0;
}

在这里插入图片描述

命名空间的其他注意事项

命名空间还有很多可以单独拎出来讲的东西:博主这里就精挑一些我们平时使用命名空间需要注意事项来讲一下:

命名空间与头文件的关系

  • 避免在头文件中使用 using namespace:可能导致命名冲突扩散到包含该头文件的所有代码。

    // myheader.h (错误示例!)
    using namespace std;  // ❌ 污染所有包含该头文件的源文件
    

命名空间的全局可见性

  • 不同文件的同名命名空间会自动合并

    // File1.cpp
    namespace Shared 
    {void func1();
    }// File2.cpp
    namespace Shared  //与File1中的Shared合并
    {  void func2();
    }
    

---------------输入&输出---------------

C++的输入&输出是什么?

cincout:是 C++ 标准库中用于标准输入输出的流对象,用于实现控制台程序的输入和输出操作。

  • 它们定义在 <iostream> 头文件中。
  • 它们属于 std 命名空间。

标准输入流 (cin):对应键盘输入,类型为 istream

  • cin 通过 提取运算符 (>>) 从键盘读取数据到变量

标准输出流 (cout):对应控制台输出,类型为 ostream

  • cout 通过 插入运算符 (<<) 将数据输出到控制台

它们是面向对象的 I/O 方式,比 C 语言的 scanfprintf 更安全、更灵活。

C++的cin和cout相较于C语言的输入和输出有什么优势?

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;int main()
{//1.定义各种类型的变量int a;double b;char c;printf("-------------使用C风格进行输入&输出-------------\n");//2.使用C风格进行输入赋值scanf("%d %lf %c ", &a, &b, &c);//3.使用C风格进行输出printf("%d %lf %c\n", a, b, c);cout << "-------------使用C++风格进行输入&输出-------------" << endl;//4.使用C++风格进行输入赋值cin >> a >> b >> c;//5.使用C++风格进行输出cout << a << " " << b << " " << c << " " << endl;return 0;
}

在这里插入图片描述

特性scanf / printfcin / cout
类型安全❌ 需手动匹配格式符✔️ 自动类型推导
扩展性❌ 仅支持基本类型✔️ 支持自定义类型的 <<>>
性能✔️ 更快⚠️ 稍慢(同步问题)

关于cin和cout还有哪些需要注意事情?

<<: 运算符可连续使用,按顺序输出表达式的值

endl: 是一个函数,流插入输出时,相当于插入一个换行符,同时刷新输出缓冲区(立即显示内容)

\n: 仅换行,不强制刷新缓冲区(性能略优,但需注意输出时机)


>>:自动跳过空白字符(空格、制表符、换行符),并尝试将输入转换为目标类型。

  • 读取字符串时,cin 默认在遇到空格时停止,因此无法读取包含空格的完整名称(Alice Smith 会被截断为 Alice
功能语法说明
输出cout << value;使用 << 插入运算符,支持链式调用
输入cin >> variable;使用 >> 提取运算符,跳过空白字符
读取整行getline(cin, str);读取包含空格的字符串
格式化输出cout << setprecision(2);需要 <iomanip> 头文件

coutcin 为保证类型安全,性能略低于 C 的 printfscanf

可通过以下三句话可以将cin和cout的输入输出速度提升2-3倍

ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);

下面是算法竞赛中常用的解绑三件套的模板和详细的注释:

#include <iostream>
using namespace std;int main()
{/* ==============================================* 【IO性能优化关键代码】*  以下三行用于提高C++标准IO流的执行效率*  适用于需要高速IO的场景(如算法竞赛)* ==============================================*//*----------第一步:关闭C++标准流与C标准库的同步----------*/// - 默认情况下,C++的cin/cout与C的stdin/stdout保持同步以保证混用时的安全性// - 关闭后可以提高速度,但不能再混用C/C++的IO函数(如:printf/cin混用)ios_base::sync_with_stdio(false);/*----------第二步:解绑cin与cout的关联----------*/// - 默认情况下,cin操作会先自动刷新cout的缓冲区(保证交互式程序的正确性)// - 解绑后进一步提升速度,但需要手动控制缓冲区刷新(如:用endl或flush)cin.tie(nullptr);/*----------第三步:解绑cout与cerr/clog的关联(非必须,但某些编译器需要)----------*/// - 进一步减少不必要的缓冲区同步cout.tie(nullptr);/* ==============================================* 【注意事项】*  使用这些优化后:*  1. 禁止混用C/C++的IO函数(如不能用printf + cin)*  2. 需要显式刷新缓冲区(如cout << endl;)*  3. 适用于纯C++ IO且数据量大的场景(如:10万+次读写)* ==============================================*/return 0;
}

---------------缺省参数---------------

什么是缺省参数?

缺省参数(Default Arguments):是指在函数声明定义时为参数指定一个默认值。

  • 当函数调用时,如果没有为该参数传递实际参数,就会使用这个默认值。

缺省参数的语法返回类型 函数名(类型 参数名 = 默认值);

缺省参数的使用案例:

/*--------------------------C++的缺省参数--------------------------*/
#include <iostream>
using namespace std;/*------------简单的了解缺省参数------------*/void Func(int a = 0)  // 参数a的默认值为0
{// 输出参数a的值cout << "a = " << a << endl;
}int main()
{//情况1:不传递参数,使用默认值cout << "调用Func():" << endl;Func();    // 等效于Func(0)// 输出结果:a = 0//情况2:传递明确参数值cout << "\n调用Func(10):" << endl;Func(10);  // 覆盖默认值,a被赋值为10// 输出结果:a = 10return 0; 
}

在这里插入图片描述

缺省参数的有哪几种?

全缺省参数:函数的所有参数都有默认值

半缺省参数:函数的部分参数有默认值,且有默认值的参数必须放在形参列表的右侧

  • 从右往左依次连续缺省,不能间隔跳跃给缺省值

全缺省参数和半缺省参数的使用案例:

/*------------------全缺省参数and半缺省参数------------------*//*** @brief 演示全缺省参数的函数* @param a 第一个参数,默认值为10* @param b 第二个参数,默认值为20* @param c 第三个参数,默认值为30* @note* - 全缺省参数:所有参数都有默认值* - 调用时可传递0~3个参数* - 缺省参数必须从右向左连续定义*/
void Func1(int a = 10, int b = 20, int c = 30)
{cout << "a = " << a;cout << " b = " << b;cout << " c = " << c << endl;
}/*** @brief 演示半缺省参数的函数* @param a 必须传入的参数(无默认值)* @param b 可选参数,默认值为10* @param c 可选参数,默认值为20* @note* - 半缺省参数:部分参数有默认值* - 必须从右向左连续缺省* - 调用时至少传递1个参数(对应a)*/
void Func2(int a, int b = 10, int c = 20)
{cout << "a = " << a;cout << " b = " << b;cout << " c = " << c << endl;
}int main()
{// 测试Func1的全缺省调用cout << "----- Func1全缺省测试 -----" << endl;Func1();        // 使用全部默认值:a=10, b=20, c=30Func1(1);       // a=1, b和c用默认值:b=20, c=30Func1(1, 2);    // a=1, b=2, c用默认值:c=30Func1(1, 2, 3); // 覆盖所有默认值:a=1, b=2, c=3// 测试Func2的半缺省调用cout << "----- Func2半缺省测试 -----" << endl;Func2(100);         // a必须传值:a=100, b和c用默认值:b=10, c=20Func2(100, 200);    // a=100, b=200, c用默认值:c=20Func2(100, 200, 300); // 覆盖所有参数:a=100, b=200, c=300return 0;
}

在这里插入图片描述

使用缺省参数时的注意事项有哪些?

特性说明示例
从右向左连续缺省参数必须从参数列表最右侧开始连续定义void func(int a, int b=1, int c=2) ✔️
void func(int a=0, int b)
调用时从左匹配实参按从左到右顺序匹配形参,不能跳过参数func(10)a=10,b=1,c=2
func(10,20)a=10,b=20,c=2
单次定义原则如果函数在头文件中声明并指定了缺省参数,在源文件中定义时不能再重复指定缺省参数,否则会导致重复定义错误。头文件:void foo(int x=5);
源文件:void foo(int x) {...}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

C++中引入缺省参数有什么好处?

疑问:可能有很多的小伙伴们在学习了缺省参数后,会感慨它有什么用处呢?

有这样的疑问是很正常的,接下来博主将使用C++的缺省参数重新实现一下我们在《数据结构初阶》中学习的顺序栈的其中的一个接口函数:顺序栈的初始化,带你领略一下缺省参数的牛逼厉害之处。

------------------------------Stack.h-------------------------------
#include <iostream>
#include <assert.h>
using namespace std;typedef int STKDataType;
typedef struct Stack
{STKDataType* a;int top;int capacity;
}STK;void STKInit(STK* pstk, int n = 4); //这里稍微注意一下;由于单次定义原则所以我们一般在函数声明时指定缺省参数------------------------------Stack.cpp-----------------------------#include "Stack.h"void STKInit(STK* pstk, int n) //缺省参数不能声明和定义同时给,所以定义时候我们没有给缺省参数
{assert(pstk);assert(n > 0);pstk->a = (STKDataType*)malloc(n * sizeof(STKDataType));pstk->top = 0;pstk->capacity = n;
}------------------------------Test.cpp-----------------------------#include "Stack.h"int main()
{STK s1;STKInit(&s1);//确定知道要插入1024个数据, 初始化时一把开好, 避免扩容STK s2;STKInit(&s2, 1024);return 0;
}

通过阅读上面的代码,小伙伴们你们是不是已经体会到缺省参数的好处了呢?

是不是在之前无论我们是否知道栈的初始空间的大小,栈的空间都要经过从4、8、16、32、……、二倍二倍的进行扩容的一个过程。

但是如果我们事先已经知道了栈的存储空间,例如是1024字节,那么是不是我们可以在定义栈的时候就一次性的将空间开辟好,也就相当于省去了10次扩容的时间消耗对吧,所以说缺省参数是很有价值的。

---------------函数重载---------------

什么是函数重载?

函数重载(Function Overloading):是指在同一个作用域内,可以有多个同名函数,但是这些函数的参数列表(参数个数参数类型参数顺序)必须不同 。

  • 编译器根据函数调用时提供的实参信息来确定具体调用哪个函数。
  • 函数的返回值类型不能作为函数重载的依据。

满足函数重载的条件有哪些?

规则说明正确案例
参数个数不同在同一作用域内,同名函数的参数个数必须有差异,这样编译器才能根据调用时传入参数的数量来区分调用哪个函数int add(int a, int b);
int add(int a, int b, int c);
参数类型不同同名函数的参数类型至少有一个不一样,编译器依据实参类型匹配对应的函数版本int add(int a, int b);
double add(double a, double b);
参数顺序不同同名函数的参数顺序不一致,也可构成重载,编译器会根据参数传入顺序判断调用哪个函数void print(int num, char ch);
void print(char ch, int num);

注意事项仅返回值类型不同不能构成函数重载

在这里插入图片描述

三种函数重载的示例:

/*-------------------------三种函数重载的案例-------------------------*/
#include <iostream>
using namespace std;/*------------------重载案例1:参数个数不同------------------*//*** @brief 无参版本函数*/
void f()
{cout << "调用 f()" << endl;
}/*** @brief 单参版本函数* @param a 整型参数*/
void f(int a)
{cout << "调用 f(int a)" << endl;
}/*------------------重载案例2:参数类型不同------------------*/
/*** @brief 函数重载示例2:参数类型不同* @param left 第一个整数操作数* @param right 第二个整数操作数* @return 两数之和* @note 与下面的double版本构成重载*/
int add(int left, int right)
{cout << "调用 int add(int left, int right)" << endl;return left + right;
}/*** @brief 函数重载示例2:参数类型不同* @param left 第一个浮点数操作数* @param right 第二个浮点数操作数* @return 两数之和* @note 与上面的int版本构成重载*/
double add(double left, double right)
{cout << "调用 double add(double left, double right)" << endl;return left + right;
}/*------------------重载案例3:参数顺序不同------------------*/
/*** @brief 参数顺序:int在前,char在后*/
void f(int a, char b)
{cout << "调用 f(int a, char b)" << endl;
}/*** @brief 参数顺序:char在前,int在后*/
void f(char b, int a)
{cout << "调用 f(char b, int a)" << endl;
}int main()
{// 测试参数个数不同的重载f();        // 调用无参版本f(10);      // 调用int参数版本// 测试类型不同的重载add(10, 20);        // 调用int版本add(10.1, 20.2);    // 调用double版本// 测试参数顺序不同的重载f(10, 'a'); // 调用(int, char)版本f('a', 10); // 调用(char, int)版本return 0;
}

在这里插入图片描述

还有哪些特殊的函数重载?

规则说明正确案例
const 修饰符差异函数参数的顶层 const(如const int)不能构成重载,但底层 const(如int* const vs const int*)可以void func(int* ptr);
void func(const int* ptr);
(底层 const 不同)
指针类型差异函数参数为不同类型的指针(如普通指针与常量指针)可以构成重载void func(int* ptr);
void func(int* const ptr);
(顶层 const 不同)
引用与值类型差异函数参数为值类型和引用类型可以构成重载void func(int a);
void func(int& a);
成员函数的 const 重载类的成员函数是否为 const 可以构成重载,用于区分对常量对象和非常量对象的调用int getValue() const;
int getValue();
模板参数实例化不同函数模板通过不同的模板参数实例化可以生成重载函数template<typename T> void func(T a);
template<> void func(int a);(显式特化)

注意:对于初学C++的萌新这里可以先作为了解,不作为掌握的内容。

函数重载和缺省参数有什么不同?

函数重载与缺省参数二者都能实现灵活调用函数,但原理不同。

  • 函数重载:是多个同名函数,参数列表不同。

  • 缺省参数:是一个函数,参数有默认值。

特性缺省参数函数重载
实现方式单一函数扩展参数多个同名函数
适用场景参数有明确默认值参数类型/数量有本质差异
灵活性行为一致,仅参数值变化可完全改变函数行为

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[USACO1.5] 八皇后 Checker Challenge Java

import java.util.*;public class Main {// 标记 对角线1&#xff0c;对角线2&#xff0c;所在x轴 是否存在棋子static boolean[] d1 new boolean[100], d2 new boolean[100], d new boolean[100]; static int n, ans 0;static int[] arr new int[14]; // 记录一轮棋子位置…

云服务器Xshell登录拒绝访问排查

根据你的描述&#xff0c;使用Xshell 8登录云服务器时显示“拒绝访问”&#xff0c;可能涉及多个原因。以下结合搜索结果整理出排查和解决方法&#xff0c;按优先级排序&#xff1a; 一、检查基础网络与端口连通性 本地网络与服务器IP是否可达 在本地电脑的CMD中执行 ping 服务…

Python爬虫实战:研究urlunparse函数相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上的数据量呈现出指数级增长。如何从海量的网页数据中高效地获取有价值的信息,成为了学术界和工业界共同关注的问题。网络爬虫作为一种自动获取网页内容的技术,能够按照预定的规则遍历互联网上的网页,并提取出所需…

Spring AI学习一

随着Chatpt的火爆&#xff0c;现在Spring官方也开始支持AI了并推出了Spring AI框架&#xff0c;目前还没发布正式版本&#xff0c;这里可以先看一下官方依赖的版本。 Spring官网地址可以看这里&#xff1a;Spring | Home 目前官网上是有这两个版本&#xff1a;1.0.0和1.1.0-SN…

reverse笔记

一&#xff0c;strcat的使用方法&#xff08;在攻防世界中刷题时遇到的&#xff09; 二&#xff0c;壳&#xff08;做题遇到过但是一直不是很理解&#xff0c;今天查了一下&#xff09; 壳是一种软件保护技术&#xff0c;能够防止程序被轻易地分析和修改。 总而言之&#xff0…

spring4第7-8课-AOP的5种通知类型+切点定义详解+执行顺序

继续学习&#xff0c;方便自己复查记录 ①AOP简介&#xff1a; 面向切面编程(也叫面向方面编程)&#xff1a;Aspect Oriented Programming(AOP)。 Spring框架中的一个重要内容。。 通过预编译方式和运行期间动态代理实现在不修改源代码的情况下给程序动态统一添加功能…

EscapeX:去中心化游戏,开启极限娱乐新体验

VEX 平台推出全新去中心化游戏 EscapeX&#xff08;数字逃脫&#xff09;&#xff0c;创新性地将大逃杀玩法与区块链技术相融合。用户不仅能畅享紧张刺激的解谜过程&#xff0c;更能在去中心化、公正透明的环境中参与游戏。EscapeX 的上线&#xff0c;为 VEX 生态注入全新活力&…

Multi Agents Collaboration OS:Web DeepSearch System

背景&#xff1a;多智能体协作驱动网络信息处理的范式革新 随着大型语言模型&#xff08;LLM&#xff09;能力的突破性进展&#xff0c;人工智能正从“单点赋能”向“系统协同”演进。传统单一智能体在复杂业务场景中逐渐显露局限&#xff1a;面对需多维度知识整合、动态任务拆…

React 第五十三节 Router中 useRouteError 的使用详解和案例分析

前言 useRouteError 是 React Router v6.4 引入的关键错误处理钩子&#xff0c;用于在 路由错误边界&#xff08;Error Boundary&#xff09; 中获取路由操作过程中发生的错误信息。 它提供了优雅的错误处理机制&#xff0c;让开发者能够创建用户友好的错误界面。 一、useRou…

[arthas]arthas安装使用

arthas是阿里开源的一个java线上监控以及诊断工具&#xff0c;在docker容器中我们无需重启服务&#xff0c;也不用更改代码&#xff0c;就可以完成对应用内存、线程、日志级别的修改、方法调用的出入参、异常监测、执行耗时等&#xff0c;xxxx.xxxx.xxxxx为脱敏内容 1. 在docke…

Flask-Babel 使用示例

下面创建一个简单的 Flask-Babel 示例&#xff0c;展示如何在 Flask 应用中实现国际化和本地化功能。这个示例将包括多语言支持&#xff08;中文和英文&#xff09;、语言切换功能以及翻译文本的使用。 项目结构 我们将创建以下文件结构&#xff1a; 1. 首先&#xff0c;创…

[论文阅读] 软件工程 | 量子计算如何赋能软件工程(Quantum-Based Software Engineering)

arXiv:2505.23674 [pdf, html, other] Quantum-Based Software Engineering Jianjun Zhao Subjects: Software Engineering (cs.SE); Quantum Physics (quant-ph) 量子计算如何赋能软件工程 我们在开发软件时&#xff0c;常常会遇到一些棘手的问题。比如&#xff0c;为了确保软…

Ansible 进阶 - Roles 与 Inventory 的高效组织

Ansible 进阶 - Roles 与 Inventory 的高效组织 如果说 Playbook 是一份完整的“菜谱”,那么 Role (角色) 就可以被看作是制作这道菜(或一桌菜)所需的标准化“备料包”或“半成品组件”。例如,我们可以有一个“Nginx Web 服务器安装配置 Role”、“MySQL 数据库基础设置 Ro…

青少年编程与数学 01-011 系统软件简介 04 Linux操作系统

青少年编程与数学 01-011 系统软件简介 04 Linux操作系统 一、Linux 的发展历程&#xff08;一&#xff09;起源&#xff08;二&#xff09;早期发展&#xff08;三&#xff09;成熟与普及&#xff08;四&#xff09;移动与嵌入式领域的拓展 二、Linux 的内核与架构&#xff08…

将图形可视化工具的 Python 脚本打包为 Windows 应用程序

前文我们已经写了一个基于python的tkinter库和matplotlib库的图形可视化工具。 基于Python的tkinter库的图形可视化工具&#xff08;15种图形的完整代码&#xff09;:基于Python的tkinter库的图形可视化工具&#xff08;15种图形的完整代码&#xff09;-CSDN博客 在前文基础上&…

【Kotlin】简介变量类接口

【Kotlin】简介&变量&类&接口 【Kotlin】数字&字符串&数组&集合 【Kotlin】高阶函数&Lambda&内联函数 【Kotlin】表达式&关键字 文章目录 Kotlin_简介&变量&类&接口Kotlin的特性Kotlin优势创建Kotlin项目变量变量保存了指向对…

OpenCV种的cv::Mat与Qt种的QImage类型相互转换

一、首先了解cv::Mat结构体 cv::Mat::step与QImage转换有着较大的关系。 step的几个类别区分: step:矩阵第一行元素的字节数step[0]:矩阵第一行元素的字节数step[1]:矩阵中一个元素的字节数step1(0):矩阵中一行有几个通道数step1(1):一个元素有几个通道数(channel()) cv::Ma…

搭建基于VsCode的ESP32的开发环境教程

一、VsCode搜索ESP-IDF插件 根据插件处搜索找到ESP-IDF并安装 安装完成 二、配置安装ESP-IDF 配置IDF 按照如下配置&#xff0c;点击安装 安装完成 三、使用案例程序 创建一个闪光灯的例子程序&#xff0c;演示程序编译下载。 选择blink例子&#xff0c;闪烁LED的程序 选…

企业培训学习考试系统源码 ThinkPHP框架+Uniapp支持多终端适配部署

在数字化转型浪潮下&#xff0c;企业对高效培训与精准考核的需求日益迫切。一套功能完备、多终端适配且易于定制的培训学习考试系统&#xff0c;成为企业提升员工能力、检验培训成果的关键工具。本文给大家分享一款基于 ThinkPHP 框架与 Uniapp 开发的企业培训学习考试系统&…

【PmHub面试篇】PmHub集成Redission分布式锁保障流程状态更新面试专题解析

你好&#xff0c;欢迎来到本次关于PmHub整合TransmittableThreadLocal (TTL)缓存用户数据的面试系列分享。在这篇文章中&#xff0c;我们将深入探讨这一技术领域的相关面试题预测。若想对相关内容有更透彻的理解&#xff0c;强烈推荐参考之前发布的博文&#xff1a;【PmHub后端…