C++基础入门(缺省参数,函数重载,引用)

缺省参数

概念

缺省参数 (又称默认参数)是指在函数声明或定义时为形参指定一个默认值,当调用函数时,如果调用者没有提供该参数的实际值,编译器会自动使用预先设定的默认值

缺省函数的使用

cpp 复制代码
#include<iostream>
using namespace std;
 
void Func(int a = 0)
{
	cout << a << endl;
}
 
int main()
{
	Func(); 
	Func(10); 
	return 0;
}

第一个func函数没有传参,所以就会调用缺省值,第二个func函数传10,就会调用传递的值

全缺省就是全部形参给缺省值,半缺省就是部分形参给缺省值。C++规定半缺省参数必须从右往左依次连续给予缺省值不能间隔跳跃给缺省值

cpp 复制代码
#include <iostream>
using namespace std;
 
// 全缺省 
void Func1(int a = 10, int b = 20, int c = 30)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << "\n" << endl;
}
// 半缺省 
void Func2(int a, int b = 10, int c = 20)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << "\n" << endl;
}
int main()
{
	Func1();
	Func1(1);
	Func1(1, 2);
	Func1(1, 2, 3);
	Func2(100);
	Func2(100, 200);
	Func2(100, 200, 300);
	return 0;
}

缺省函数的好处

允许调用者只传递必要的参数,省略的参数自动使用默认值,使代码更简洁

避免为不同参数组合编写多个重载函数,一个函数即可覆盖多种调用场景

函数可以同时满足通用需求和特殊需求:大多数情况使用默认值,特殊需求时显式传参。

为参数设定常用默认值,降低使用门槛,提高代码的可读性和易用性。

新增参数时,只要设为默认值,原有调用代码无需修改,保持向后兼容

在类构造函数中使用默认参数,可以方便地提供多种对象创建方式

想象一下:你妈叫你吃饭,只说"快过来",你就自动知道要带筷子、坐老位置、先喝汤------这就是缺省参数!它让函数在调用者"偷懒"的时候,自己把缺的参数补上,堪称编程界的"自动脑补侠"

函数重载

概念

想象一下,你有个朋友叫"小明",但他同时会修电脑、会做饭、会修马桶------每次你喊"小明过来!",他就会根据你当时的需求自动切换技能:你说"电脑卡了",他变程序员;你说"肚子饿了",他变厨师。这就是函数重载

函数重载允许你在同一个作用域里,定义多个同名函数 ,只要它们的参数列表不同,编译器会根据你调用时传的实参,自动派发对应的函数去执行

函数重载的使用

cpp 复制代码
#include<iostream>
using namespace std;
int Add(int a, int b)
{
	return a + b;
}
double Add(double a, double b)
{
	return a + b;
}
void func3()
{
	cout << "func3:" << endl;
}
void func4(int a)
{
	cout << "func4:"<< a << endl;
}
int main()
{
	int ret1=Add(1, 2);
	double ret2=Add(1.1, 2.2);
	cout << ret1 << endl;
	cout << ret2 << endl;
	func3();
	func4(100);
	return 0;
}

所以我们发现,只要形参不同,编译器就能自己识别不同函数,但是返回值不同,不能做为重载条件

cpp 复制代码
void func(int a)
{
	cout << "func(int a)";
}
int func(int a)
{
	cout << "func(double a)";
}
int main()
{
	func(1);
	return 0;
}
cpp 复制代码
void func()
{
	cout << "func()";
}
void func(int a=10)
{
	cout << "func(int a)";
}
int main()
{
	func();
	return 0;
}

这是因为我们定义了两个func函数,一个没有形参,一个有缺省值,我的函数既可以匹配没有形参的func,也可以匹配有缺省值的函数,这样的话编译器就不知道该匹配哪一个函数

引用

概念

引用 就是给一个已经存在的变量取一个别名,它俩共用同一块内存空间,你对引用做的任何操作,都会直接作用在原变量身上------相当于给同一个人起了两个名字:你喊"张大帅"和喊"二狗子",都是同一个人回头

cpp 复制代码
int main()
{
	int a = 0;
	//引用:b和c是a的别名
	int& b = a;
	int& c = a;
	int& d = b;
	++d;
	cout << &a << endl;
	cout << &b << endl;
	cout << &c << endl;
	cout << &d << endl;
    return 0;
}

这是不是就证明了引用的地址和变量的地址在同一块内存

那我们再来看一下值有什么变化

cpp 复制代码
int main()
{
	int a = 0;
	//引用:b和c是a的别名
	int& b = a;
	int& c = a;
	int& d = b;
	++d;
	cout << a << endl;
	cout << b << endl;
	cout << c << endl;
	cout << d << endl;
	return 0;
}

我们最先定义的a的值是0,现在就全都变为1了

引用的特点

引用在定义时必须初始化

cpp 复制代码
int main()
{
	int a = 0;
	int& ra;
	return 0;
}

引用一但引用一个实体,就不能再引用其他实体

cpp 复制代码
int main()
{
	int a = 0;
	int& b=a;
	int c = 1;
	b = c;
	cout << &a << endl;
	cout << &b << endl;
	cout << &c << endl;
	return 0;
}

当程序执行到"b=a"的时候,可能朋友们就会说让 b 引用 c,大错特错, 引用一旦绑定,终身无法改嫁, b 从出生那一刻就死心塌地跟着 a,这一行 b = c 的真实含义是:**把 c 的值赋给 b 所引用的变量(也就是 a),**从地址上我们也可以看出来,b和c的地址是不一样的

引用的使用

之前大家都写学习过地址,都学过传值调用 和**传址调用,**如果要改变值就要使用传址调用,而现在我们已经学了引用,那我们就可以用引用来替代传址调用

cpp 复制代码
void Swap(int& rx, int& ry) 
{
	int tmp = rx;
	rx = ry;
	ry = tmp;
}
int main()
{
	int x = 0, y = 1;
	cout << x << " " << y << endl;
	Swap(x, y);
	cout << x << " " << y << endl;
	return 0;
}

这里rx是x的别名,ry是y的别名,所以这里我们就不用去调用地址,直接引用就可以了

const对象的引用

权限放大可以引用一个const对象,但是必须用const引用。const引用也可以引用普通对象 ,因为对象的访问权限 在引用过程中可以缩小 ,但是不能放大

cpp 复制代码
int main()
{
	const int a = 10;
    //权限放大
	int& b = a;
    return 0;
}   

这就是我们的权限放大,当整型int被const修饰时说明该变量只能读取不能改写 ,如果该变量没有被const修饰那这个变量既可读也可写,权限只能缩小不能放大 ,但是b却没有错误,说明这个时候b是既可读也可写 ,b是a的别名,b就从只能读取 放大到了既可读也可写 ,这就是权限放大

那我们想要a和b平起平坐,那我们就需要使用到const

cpp 复制代码
int main()
{
	//放大权限
	const int a = 10;
	const int& b = a;     
	return 0;
}
cpp 复制代码
int main()
{
	//缩小权限
	int a = 10;
	const int& b = a;     
	return 0;
}

给常量取别名需要用const修饰

cpp 复制代码
int main()
{   
	double e = 12.34;
	int i = e;
	const int& ri = e;
	return 0;
}

e给int的时候会产生隐式转换 ,而隐式转换会产生临时对象(还有表达式相加),把d的整数部分拿出来放在临时对象,ri引用临时对象,而临时对象具有**常性,**需要用const修饰

指针和引用的关系

  • 本质:指针是存地址的独立变量,引用是变量别名
  • 初始化:指针可延迟初始化 / 置空,引用必须绑定变量且不可改指向
  • 访问:指针需 * 解引用,引用直接使用
  • 空值:指针可空(易出野指针),引用不能为空(更安全)
  • 灵活性:指针支持多级 / 改指向,引用功能受限但语法简洁
  • 场景:函数参数 / 返回值优先用引用,需空值 / 改指向用指针

nullptr

NULL 实际是一个,在传统的C头文件 (stddef.h)中

cpp 复制代码
#ifndef NULL
    #ifdef __cplusplus
        #define NULL 0
    #else
        #define NULL ((void *)0)
    #endif
#endif

在C++中NULL被定义为字面常量0,而在C中被定义为无类型指针 (void*) 的常量。不论采取何种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,本想通过 f(NULL) 调用指针版本的 f(int*) 函数,但是由于NULL被定义成0,变成了调用了 f(int x) ,因此与程序的初衷相悖。而只有将 NULL 类型强转成 int* 才可实现

cpp 复制代码
void f(int x)
{
	cout << "f(int x)" << endl;
}
void f(int* ptr)
{
	cout << "f(int* ptr)" << endl;
}

int main()
{
	f(0);
	f(NULL);
	f((int*)NULL);
    //f((void*)NULL);编译错误
	return 0;
}

而到了C++11后就引入了nullptr,nullptr是一个特殊的关键字,nullptr是一种特殊类型的字面量,它可以转换成任意其他类型的指针类型。使用nullptr定义空指针可以避免类型转换的问题,因为nullptr只能被隐式地转换为指针类型,而不能被转换为整数类型

cpp 复制代码
void f(int x)
{
	cout << "f(int x)" << endl;
}
void f(int* ptr)
{
	cout << "f(int* ptr)" << endl;
}

int main()
{
	f(0);
	f(NULL);

	f(nullptr);
	return 0;
}

所以以后我们就不再用NULL表示空指针了,而是nullptr

C++参考文献

cplusplus.com

cppreference.com

相关推荐
我不是秋秋2 小时前
软件开发项目各角色关系解析:产品/前后端/测试如何高效协作?
java·算法·面试·职场和发展·哈希算法
Tisfy2 小时前
LeetCode 1886.判断矩阵经轮转后是否一致:模拟
算法·leetcode·矩阵·题解·模拟
XiaoLeisj3 小时前
Android Kotlin 全链路系统化指南:从基础语法、类型系统与面向对象,到函数式编程、集合操作、协程并发与 Flow 响应式数据流实战
android·开发语言·kotlin·协程
dapeng28704 小时前
分布式系统容错设计
开发语言·c++·算法
qq_417695054 小时前
代码热修复技术
开发语言·c++·算法
badhope8 小时前
Mobile-Skills:移动端技能可视化的创新实践
开发语言·人工智能·git·智能手机·github
码云数智-园园10 小时前
微服务架构下的分布式事务:在一致性与可用性之间寻找平衡
开发语言
C++ 老炮儿的技术栈10 小时前
volatile使用场景
linux·服务器·c语言·开发语言·c++
hz_zhangrl10 小时前
CCF-GESP 等级考试 2026年3月认证C++一级真题解析
开发语言·c++·gesp·gesp2026年3月·gespc++一级