《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/bicheng/84160.shtml

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

相关文章

java综合项目开发一课一得

文章目录 Java 综合项目课程学习&#xff1a;探索与成长之路一、课程初体验&#xff1a;从理论走向实践&#xff08;一&#xff09;系统学习 Java 核心理论知识&#xff08;二&#xff09;开启首个实践项目 —— 图书管理系统 二、项目攻坚&#xff1a;挑战与突破&#xff08;一…

JuiceFS v1.3-Beta2:集成 Apache Ranger,实现更精细化的权限控制

在大数据场景中&#xff0c;文件系统和应用组件的权限管理至关重要。在最新发布的 JuiceFS 社区版 v1.3-Beta 2 中&#xff0c;JuiceFS 引入了与 Apache Ranger 的集成&#xff0c;提供了更为灵活和细粒度的权限控制解决方案。 本文将介绍 JuiceFS 社区版如何与 Apache Ranger…

6月8日day48打卡

随机函数与广播机制 知识点回顾&#xff1a; 随机张量的生成&#xff1a;torch.randn函数卷积和池化的计算公式&#xff08;可以不掌握&#xff0c;会自动计算的&#xff09;pytorch的广播机制&#xff1a;加法和乘法的广播机制 ps&#xff1a;numpy运算也有类似的广播机制&…

计算机常用快捷键分类汇总,涵盖 Windows、macOS 以及通用软件场景

一、系统通用快捷键 功能Windows 快捷键macOS 快捷键复制Ctrl CCommand C粘贴Ctrl VCommand V剪切Ctrl XCommand X撤销Ctrl ZCommand Z全选Ctrl ACommand A保存Ctrl SCommand S打印Ctrl PCommand P新建窗口/标签页Ctrl NCommand N关闭当前窗口/标签页Ctrl WC…

ES6中的Map与Set数据结构的简单应用

一、Map定义和基本用法 Map是一种键值对集合&#xff0c;其中键和值都可以是任何类型&#xff08;对象、原始值等&#xff09;。与普通对象不同&#xff0c;Map保持键值对的插入顺序&#xff0c;并且允许使用任何类型的键。 1、创建Map const map new Map()2、添加键值对。…

25.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--单体转微服务--用户服务接口

用户管理是任何系统的基础功能之一&#xff0c;本篇介绍了如何实现一个完整的用户管理模块&#xff0c;包括用户信息的增删改查、用户状态管理、分页查询、数据验证和权限控制。核心代码实现部分涵盖了控制器&#xff08;UserController&#xff09;、服务接口&#xff08;IUse…

基于深度学习的无人机轨迹预测

完整代码见文末 随着无人机技术的不断发展,无人机在农业、物流、监控等领域的应用日益广泛。精准的轨迹预测不仅能够提高无人机飞行的效率和安全性,还能在应对复杂环境下的突发状况时做出迅速反应。因此,基于深度学习的无人机轨迹预测已成为当前研究和应用的热门方向。 无…

AUTOSAR实战教程--DoIP_02_诊断链路建立流程

第一步&#xff1a;DoIP实体车辆声明/诊断仪车辆识别请求 打开激活线以后&#xff0c;DoIP实体发的三帧车辆声明报文。其中包含了DoIP实体的诊断逻辑地址&#xff08;可以类比DoCAN的物理请求/响应地址&#xff09;&#xff0c;对应车辆的VIN码&#xff08;若已配置&#xff0…

跟我学c++中级篇——多线程中的文件处理

一、文件处理 作为IO处理的一种重要场景&#xff0c;文件处理是几乎所有编程都无法绕过的一个情况。稍微复杂的一些的程序都可能需要文件处理&#xff0c;不管这种文件处理对开发者来说是显式的还是隐式的。相对于其它语言&#xff0c;C并未提供多么好的文件处理API接口&#…

Flutter知识点汇总

Flutter架构解析 1. Flutter 是什么?它与其他移动开发框架有什么不同? Flutter 是 Google 开发的开源移动应用开发框架,可用于快速构建高性能、高保真的移动应用(iOS 和 Android),也支持 Web、桌面和嵌入式设备。。它与其他移动开发框架(如 React Native、Xamarin、原…

【会员专享数据】1980—2022年中国逐日月年潜在蒸散发栅格数据

气象数据是我们在各项研究中都经常使用的数据&#xff0c;尤其是高精度的气象数据应用价值非常高。 之前我们分享过研究者张凌, 胡英屹等发布在国家冰川冻土沙漠科学数据中心平台上的nc格式的1980—2022年中国高分辨率逐日、逐月、逐年气象数据&#xff01;很多小伙伴拿到数据…

前端打包工具简单介绍

前端打包工具简单介绍 一、Webpack 架构与插件机制 1. Webpack 架构核心组成 Entry&#xff08;入口&#xff09; 指定应用的起点文件&#xff0c;比如 src/index.js。 Module&#xff08;模块&#xff09; Webpack 把项目当作模块图&#xff0c;模块可以是 JS、CSS、图片等…

工业控制核心引擎高性能MCU——MM32F5370

RAMSUN提供的MM32F5370搭载180MHz Arm China Star-MC1处理器&#xff0c;集成DSP、FPU与三角函数加速单元&#xff08;CORDIC&#xff09;&#xff0c;轻松应对复杂算法需求。其技术亮点包括&#xff1a; 超高精度PWM&#xff1a;8通道208ps级高精度PWM输出&#xff0c;满足储能…

AI架构师修炼之道

1 AI时代的架构革命 与传统软件开发和软件架构师相比&#xff0c;AI架构师面临着三重范式转换&#xff1a; 1.1 技术维度&#xff0c;需处理异构算力调度与模型生命周期管理的复杂性&#xff1b; 1.2 系统维度&#xff0c;需平衡实时性与资源约束的矛盾&#xff1b; 1.3 价…

数学建模期末速成 主成分分析的基本步骤

设有 n n n个研究对象&#xff0c; m m m个指标变量 x 1 , x 2 , ⋯ , x m x_1,x_2,\cdots,x_m x1​,x2​,⋯,xm​&#xff0c;第 i i i个对象关于第 j j j个指标取值为 a i j a_{ij} aij​,构造数据矩阵 A ( a i j ) n m A\left(\begin{array}{c}a_{ij}\end{array}\right)_{…

博图 SCL 编程技巧:灵活实现上升沿与下降沿检测案例分享(上)

博图 SCL 编程技巧&#xff1a;灵活实现上升沿与下降沿检测案例分享 在 PLC 编程中&#xff0c;检测信号从 0 变为 1 (上升沿) 或从 1 变为 0 (下降沿) 是最基础也是最关键的操作之一。它常用于启动单次动作、计数、状态切换等场景。在西门子 TIA Portal 环境中&#xff0c;虽…

深度学习入门Day3--鱼书学习(2)

这俩天刚忙完答辩的事情&#xff0c;终于有时间学习了 一、3层神经网络实现 1.本节中的符号使用说明。 w 12 ( 1 ) w_{12}^{(1)} w12(1)​表示前一层的第2个神经元 x 2 x_{2} x2​到后一层的第一个神经元 a 1 a_{1} a1​的权重。权重右下角按照“后一层的索引号、前一层的索引…

服务器 | Centos 9 系统中,如何部署SpringBoot后端项目?

系列文章目录 虚拟机 | Ubuntu 安装流程以及界面太小问题解决 虚拟机 | Ubuntu图形化系统&#xff1a; open-vm-tools安装失败以及实现文件拖放 虚拟机 | Ubuntu操作系统&#xff1a;su和sudo理解及如何处理忘记root密码 文章目录 系列文章目录前言一、环境介绍二、 使用syst…

CNN核心机制深度解析:卷积池化原理 PyTorch实现经典网络

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文系统讲解CNN核心原理、经典网络架构和图像分类实战&#xff0c;涵盖卷积层、池化层、LeNet/AlexNet/VGG/ResNet设计思想&#xff0c;并提供CIFAR-…

6个月Python学习计划 Day 17 - 继承、多态与魔术方法

第三周 Day 4 &#x1f3af; 今日目标 理解类的继承和方法重写掌握多态思想及其实际应用了解并使用常见的魔术方法&#xff08;如 str、len 等&#xff09; &#x1f9ec; 类的继承&#xff08;Inheritance&#xff09; Python 支持单继承与多继承&#xff0c;常用语法如下&…