目录
内联函数
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;
}
1376

被折叠的 条评论
为什么被折叠?



