C++函数重载,引用和namespace

部署运行你感兴趣的模型镜像

目录

namespace命名空间

函数重载

引用

内联函数 


namespace命名空间

在C/C++中,变量、函数和后⾯要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。

简单来说namespace存在是为了避免命名冲突

#include <stdio.h>
#include <stdlib.h>

int rand = 10;
int main()
{
	printf("%d", rand);
	//出现报错,原因是程序先访问局部变量的rand后访问全局变量的rand,由于<stdlib.h>展开
	//而rand在<stdlib.h>中定义为函数,于是就出现了重定义的冲突
	return 0;
}
解决方案是引入namespace

命名空间中可以定义变量/函数/类型等,也可以嵌套定义。

namespace lpt
{
	//namespace可以定义多种元素(函数,结构体,变量,当然也可以嵌套定义)
	int rand = 10;
	int Add(int left, int right)
	{
		return left + right;
	}
	struct NODE
	{
		int data;
		struct NODE* next;
	};
	namespace GGbood
	{
		int rand = 20;
		int Add(int left, int right)
		{
			return left + right;
		}
		struct NODE
		{
			int val;
			struct NODE* next;
		};
	}
}

命名空间使用

1.指定命名空间访问。

2.using将命名空间中某个成员展开

3.全部展开(确定不存在冲突)

using namespace std;//全部展开
using  std::cout;//部分展开
using std::endl;
printf("%d\n", lpt::rand);//指定命名空间访问

缺省参数 

缺省参数是声明或定义函数时为函数的参数指定⼀个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参,缺省参数分为全缺省和半缺省参数

void func(int a = 1)
{
	cout << a << endl;
}
void func1(int a = 1, int b = 2, int c = 3)//全缺省
{
	int d = a + b + c;
	cout << d << endl;
}
void func1(int a , int b = 2, int c = 3)//半缺省
{
	int d = a + b + c;
	cout << d << endl;
}

 函数重载

C++⽀持在同⼀作用域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者类型不同

//函数重载:同一作用域同名函数,要求形参不同(个数,类型)
//类型
int Add(int left,int right)
{
	return left + right;
}
double Add(double left, double right)
{
	return left + right;
}
//个数
int function()
{
	return 10;
}
int function(int n)
{
	return n;
}
//顺序
int list(char a, int b)
{
	return b;
}
char list(int a, char b)
{
	return b;
}
//返回值不同无法构成重载
//例如:int func(int a)和double func(int a),此时编译器无法区分要调用哪一个函数
//构成重载但是报错情况:
void funcc(int n = 10)
{
	cout << n << '\n';
}
void funcc()
{
	cout << 10 << '\n';
}
 //原因是相当于缺省情况

 引用

• 引用在定义时必须初始化

• ⼀个变量可以有多个引用

• 引用⼀旦引用⼀个实体,再不能引用其他实体

格式:int& b=a;类型 & 别名 = 本体

//引用(只能对单个对象进行引用):引用只是给对象取别名,实际调用还是那个空间,他们共用一块内存空间
//格式:int& b=a;类型 & 别名 = 本体
void test01()
{
	int a = 10;
	int& b = a;//b是a的引用
	int& c = b;
	c++;
	cout << &a << endl;
	cout << &b << endl;
	cout << &c << endl;
	int x = 9;
	b = x;//此时进行赋值操作
	cout << b << endl;
}
//引用在结构体中的运用
typedef struct STList
{
	int data;
	struct STList* next;
}STList,*STNode;
//STList
typedef struct STList STList;//结构体别名
//STNode
typedef struct STList* STNode;//代表结构体指针
//链表中
void STPushBack(STList** phead, int x);
//由于采用引用则:STList ST;STList*& sst=ST;
void STPushBack(STList*& phead, int x);
//采用结构体指针则:STList*&phead=STNode phead;
void STPushBack(STNode phead, int x);
//以上三者等价
//采用引用做函数返回值
int fun(int& a)
{
	//return a;
	//造成野引用情况:int top=a;return top;
	//在上述情况中,除了局部作用域top就会被销毁,此时再想根据top返回就会造成越界访问
	int top = a;
	return top;
}
//引用究竟能不能作为返回值,最主要看的就是局部栈帧销毁之后,想引用对象还存不存在

 const引用

 

//const 引用(const 代表只读不能修改)
//正确用法:const 对象->const 引用;普通对象->const 引用
int funcn(int& b)
{
	//假设被引用的是const int&a=20;
	//会报错是因为b*3是常量表达式:因为通常会用tmp=b*3格式,此时tmp已经是常量
	//const 对象--->普通引用=权限放大
	return b * 3;
}
void test02()
{
	const int a = 99;
	//int& b = a;//权限放大--->错误
	const int& c = a;//权限平移
	int a1 = 90;
	const int& ra = a1;//权限缩小
	//涉及权限就看是不是同一块空间
	int rra = a;//仅仅是拷贝情况
	cout << funcn(a1) << endl;
}

内联函数:inline

 1.用inline修饰的函数叫做内联函数,编译时C++编译器会在调用的地方展开内联函数,这样调用内联函数就不需要建立栈帧了,就可以提高效率。

2.inline对于编译器而言只是⼀个建议,也就是说,你加了inline编译器也可以选择在调用的地方不展开,不同编译器关于inline什么情况展开各不相同,因为C++标准没有规定这个。inline适用于频繁调用的短小函数,对于递归函数,代码相对多⼀些的函数,加上inline也会被编译器忽略。(总的来说就是由编译器把关

3.inline不建议声明和定义分离到两个文件,分离会导致链接错误。

展开示意: 采用宏

#define add(a,b) ((a)+(b))

 

不展开示意:采用内联函数(没有改变编译器配置)

inline int add(int a, int b)
{
	int d = a + b;
	return d;
}

不难发现在展开的时候没有call add,而不展开的时候有call add (建立栈帧) 

 全部代码

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

//int rand = 10;
//int main()
//{
//	printf("%d", rand);
//	//出现报错,原因是程序先访问局部变量的rand后访问全局变量的rand,由于<stdlib.h>展开
//	//而rand在<stdlib.h>中定义为函数,于是就出现了重定义的冲突
//	return 0;
//}
//解决方案是引入namespace
#include <iostream>
using namespace std;//全部展开
using  std::cout;//部分展开
using std::endl;
namespace lpt
{
	//namespace可以定义多种元素(函数,结构体,变量,当然也可以嵌套定义)
	int rand = 10;
	int Add(int left, int right)
	{
		return left + right;
	}
	struct NODE
	{
		int data;
		struct NODE* next;
	};
	namespace GGbood
	{
		int rand = 20;
		int Add(int left, int right)
		{
			return left + right;
		}
		struct NODE
		{
			int val;
			struct NODE* next;
		};
	}
}
void func(int a = 1)
{
	cout << a << endl;
}
void func1(int a = 1, int b = 2, int c = 3)
{
	int d = a + b + c;
	cout << d << endl;
}
//函数重载:同一作用域同名函数,要求形参不同(个数,类型)
//类型
int Add(int left,int right)
{
	return left + right;
}
double Add(double left, double right)
{
	return left + right;
}
//个数
int function()
{
	return 10;
}
int function(int n)
{
	return n;
}
//顺序
int list(char a, int b)
{
	return b;
}
char list(int a, char b)
{
	return b;
}
//返回值不同无法构成重载
//例如:int func(int a)和double func(int a),此时编译器无法区分要调用哪一个函数
//构成重载但是报错情况:
void funcc(int n = 10)
{
	cout << n << '\n';
}
void funcc()
{
	cout << 10 << '\n';
}
 //原因是相当于缺省情况
  
 
////////////////////////////////////////////////////////////////////////////////
//引用(只能对单个对象进行引用):引用只是给对象取别名,实际调用还是那个空间,他们共用一块内存空间
//格式:int& b=a;类型 & 别名 = 本体
void test01()
{
	int a = 10;
	int& b = a;//b是a的引用
	int& c = b;
	c++;
	cout << &a << endl;
	cout << &b << endl;
	cout << &c << endl;
	int x = 9;
	b = x;//此时进行赋值操作
	cout << b << endl;
}
//引用在结构体中的运用
typedef struct STList
{
	int data;
	struct STList* next;
}STList,*STNode;
//STList
typedef struct STList STList;//结构体别名
//STNode
typedef struct STList* STNode;//代表结构体指针
//链表中
void STPushBack(STList** phead, int x);
//由于采用引用则:STList ST;STList*& sst=ST;
void STPushBack(STList*& phead, int x);
//采用结构体指针则:STList*&phead=STNode phead;
void STPushBack(STNode phead, int x);
//以上三者等价
//采用引用做函数返回值
int fun(int& a)
{
	//return a;
	//造成野引用情况:int top=a;return top;
	//在上述情况中,除了局部作用域top就会被销毁,此时再想根据top返回就会造成越界访问
	int top = a;
	return top;
}
//引用究竟能不能作为返回值,最主要看的就是局部栈帧销毁之后,想引用对象还存不存在


/// ///////////////////////////////////////////////////////////////////////////
//const 引用(const 代表只读不能修改)
//正确用法:const 对象->const 引用;普通对象->const 引用
int funcn(int& b)
{
	//假设被引用的是const int&a=20;
	//会报错是因为b*3是常量表达式:因为通常会用tmp=b*3格式,此时tmp已经是常量
	//const 对象--->普通引用=权限放大
	return b * 3;
}
void test02()
{
	const int a = 99;
	//int& b = a;//权限放大--->错误
	const int& c = a;//权限平移
	int a1 = 90;
	const int& ra = a1;//权限缩小
	//涉及权限就看是不是同一块空间
	int rra = a;//仅仅是拷贝情况
	cout << funcn(a1) << endl;
}
int main()
{
	printf("%d\n", lpt::rand);
	printf("%d\n", lpt::GGbood::Add(3, 4));
	printf("%p\n", rand);//默认是全局的rand
	cout << lpt::GGbood::rand << endl;
	func();
	func(23);
	func1();//全缺省
	func1(23, 5);//半缺省
	cout<<Add(1, 2)<<'\n';
	cout << Add(1.22, 3.55) << '\n';
	cout << function() << '\n';
	cout << function(90) << '\n';
	cout << list(33, 'a') << '\n';
	cout << list('a', 33) << '\n';
	//test01();
	int a = 3;
	cout<<fun(a)<<endl;
	test02();
	return 0;
}
//在汇编层面指针和引用是一样的,都需要开辟空间,所以上述top返回的时候仍会有返回值,编译器也只是报警告
//inline
//宏定义:1.直接展开 2.不受编译器控制
#include <iostream>
using namespace std;
#include"test.h"
//#define add(a,b) ((a)+(b))
//采用宏则直接展开
inline int add(int a, int b)
{
	int d = a + b;
	return d;//此时打开反汇编仍可以看到call则说明并没有展开
	//是否展开关键是看有没有call,有则说明没有展开,仍会像函数一样建立栈帧
	//并且使用内联函数是否展开还取决于编译器
	//展开条件:1.内联函数短小(一般10行以内)2.在Debug条件之下默认不展开,因为不方便调试
	//要求内联函数内容短小原因:如果有100行代码,调用1000次
	//展开:100*1000 不展开:100+1000 很明显可以看到代码量变大,可执行程序(APP,安装包)变大
	//内联函数声明和定义不能分离->在头文件直接展开,在源文件没有地址,因为编译器默认已经展开就不生成地址,用的时候就会找不到地址->报错
	//解决方法直接放头文件
}
//普通函数不能放头文件
//原因就是会生成两个一样的符号表导致冲突
// //解决方法在头文件函数之前加上static->可以改变生命周期,改变链接属性(只在当前文件可见)->本质就是不会进入符号表
//void print(int i)
//{
//	cout << i << endl;
//}
int main()
{
	cout << add(3, 4) << endl;
	print(3);
	return 0;
}

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值