C++ 基础

目录

一、命名空间;

1.如何定义;

代码举例:

嵌套定义命名空间:

2.如何使用;

(1)使用加命名空间名称及作用域限定符;

代码举例:

运行结果:

(2)使用using将命名空间中某个成员引入;

代码举例:

运行结果:

[(3)使用using namespace 命名空间名称引入(最好不要全部授权);](#(3)使用using namespace 命名空间名称引入(最好不要全部授权);)

代码举例:

运行结果:

(4)命名空间合并;

3.输入输出函数;

代码举例:

运行结果:

二、缺省函数;

1.函数定义;

代码举例:

运行结果:

2.分类;

(1)全缺省函数;

代码举例:

运行结果:

(2)半缺省函数;

代码举例:

运行结果:

(3)缺省函数声明与定义;

三、函数重载;

1.重载类型分类;

(1)类型顺序不同;

代码举例:

运行结果:

(2)参数个数不同;

代码举例:

运行结果:​编辑

(3)参数类型不同;

代码举例:

运行结果:

2.函数重载原因;

代码举例:

运行结果:

四、引用;

1.简要介绍;

代码举例:

运行结果:​编辑

结果分析:

2.引用的应用;

(1)传引用返回:

代码举例:

运行结果:

结果分析:

(2)传引用传参:

代码举例:

运行结果:

结果分析:

3.引用的限制条件;

4.权限问题;

简要介绍:

代码举例:

运行结果:

结果分析:

五、内联函数;

1.简要介绍;

代码举例:

运行结果:

结果分析:

2.常见问题;

代码举例:

运行结果:

结果分析:

3.声明和定义;

4.优缺点:

六、auto关键字;

1.简要介绍;

代码举例:

运行结果:

结果分析:

2.范围for;

代码举例:

运行结果:

结果分析:

七、nullptr;

1.简要介绍;

代码举例:

运行结果:​编辑


一、命名空间;

1.如何定义;

定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{} 中即为命名空间的成员。命名空间中可以定义变量/函数/类型;命名空间可以嵌套;同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。目的是为了解决命名冲突(新建的变量名与库的变量重名);

代码举例:

定义一个名称为bin的命名空间:

cpp 复制代码
namespace bin//命名空间可以定义变量函数函数结构体。
{
	int rand1 = 0;
	int val = 10;
	int add(int x, int y)
	{
		return x + y;
	}
	struct a
	{
		struct a* next;
		int y;
	};
	
}
嵌套定义命名空间:
cpp 复制代码
namespace bin//命名空间可以定义变量函数函数结构体。
{
	int rand1 = 0;
	int val = 10;
	int add(int x, int y)
	{
		return x + y;
	}
	struct a
	{
		struct a* next;
		int y;
	};
	namespace hhh
	{
		int rand = 1;
		int val1 = 15;
	}
}

2.如何使用;

(1)使用加命名空间名称及作用域限定符;

代码举例:
cpp 复制代码
namespace bin//命名空间可以定义变量函数函数结构体。
{
	int rand1 = 0;
	int val = 10;
	int add(int x, int y)
	{
		return x + y;
	}
	struct a
	{
		struct a* next;
		int y;
	};
	namespace hhh
	{
		int rand = 1;
		int val1 = 15;
	}
}
int main()
{
	printf("%d\n",bin::rand1);//域作用限定符
	printf("%d\n", bin::add(1, 2));
	struct bin::a x;//引用结构体的时候bin::放在struct后面。
	x.next = NULL;
	x.y = 10;
	return 0;
}
运行结果:

(2)使用using将命名空间中某个成员引入;

代码举例:
cpp 复制代码
namespace bin//命名空间可以定义变量函数函数结构体。
{
	int rand1 = 0;
	int val = 10;
	int add(int x, int y)
	{
		return x + y;
	}
	struct a
	{
		struct a* next;
		int y;
	};
	namespace hhh
	{
		int rand = 1;
		int val1 = 15;
	}
}
using bin::add;
using bin::rand1;
using bin::a;
int main()
{
	printf("%d\n", bin::hhh::rand);//::域作用限定符
	printf("%d\n", rand1);
	printf("%d\n", add(1, 2));
	a x;
    x.next = NULL;
	x.y = 10;
	printf("%d %p", x.y, x.next);
	return 0;
}
运行结果:

(3)使用using namespace 命名空间名称引入(最好不要全部授权);

代码举例:
cpp 复制代码
namespace bin//命名空间可以定义变量函数函数结构体。
{
	int rand1 = 0;
	int val = 10;
	int add(int x, int y)
	{
		return x + y;
	}
	struct a
	{
		struct a* next;
		int y;
	};
	namespace hhh
	{
		int rand = 1;
		int val1 = 15;
	}
}
using namespace bin;
int main()
{
	printf("%d\n", bin::hhh::rand);//::域作用限定符
	printf("%d\n", rand1);
	printf("%d\n", add(1, 2));
	a x;//引用结构体的时候bin::放在struct后面。
	x.next = NULL;
	x.y = 10;
	printf("%d %p", x.y, x.next);
	return 0;
}
运行结果:

(4)命名空间合并;

命名空间可以自动合并; 多个文件里相同名字的命名空间可以自动合并;(同名的变量会出错,不写或者再写一层命名空间,写在新建的命名空间里)。

3.输入输出函数;

使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件以及按命名空间使用方法使用std。cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,与"\n"类似,他们都包含在包含<iostream >头文件中。<<是流插入运算符,>>是流提取运算符。

代码举例:
cpp 复制代码
#include<iostream>//把头文件拷贝过来,std在头文件里的命名空间里。
using namespace std;
namespace jdg
{
	int ruler;
	int sheer;
}
int main()
{
	int x = 0;
	int y = 0;
	cin >> x >>y;
	cout << x << y << endl;
	cout << "top is " << jdg::ruler << endl;
	cout << "jug is" << jdg::sheer << endl;
	return 0;
}
运行结果:

二、缺省函数;

1.函数定义;

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

代码举例:
cpp 复制代码
#include<iostream>
using namespace std;
void func(int a = 1)
{
	cout << a << endl;
}
int main()
{
	func(2);//有传参就用传的参;
	func();
    return 0;
}
运行结果:

2.分类;

(1)全缺省函数;

全部参数都有缺省值;

代码举例:
cpp 复制代码
void func1(int a = 1, int b = 2,int c=3)
{
	cout << "a=="<<  a << endl;
	cout << "b==" << b << endl;
	cout << "c==" << c << endl;
}

int main()
{
	
	func1();
	func1(3);///从左往右依次传参;
	func1(3,1);
	func1(4, 5, 6);
	return 0;
}
运行结果:

(2)半缺省函数;

部分参数有缺省值;参数必须传至少一个值,缺省值必须从左往右给;

代码举例:
cpp 复制代码
#include<iostream>
using namespace std;

void func(int a, int b = 1, int c = 1)//半缺省;必须传一个,缺省值必须从左往右给;
{
	cout << a + b + c << endl;//传参数默认传给第一个;
}
int main()
{
	/*fun();*/
	/*fun(10);*/
	func(1);
	func(1, 2);
	func(1, 2,3);
	return 0;
}
运行结果:

(3)缺省函数声明与定义;

缺省参数不能在声明和定义同时给,只能在声明中给;因为如果在声明的地方给定义,多个文件包含头文件会造成重复定义,有可能出错;

三、函数重载;

C语言不允许同名函数,C++允许同名函数,但要求构成重载;(这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同);

1.重载类型分类;

(1)类型顺序不同;

代码举例:
cpp 复制代码
void func(int a, double b)
{
	cout << "void func(int a, double b)" << endl;
}
void func(double a, int b)//函数的地址是函数第一句指令的地址,只声明不定义的函数没有地址;
{
	cout << "void func(double a, int b)" << endl;
}
int main()
{
	func(1, 1.2);//call func(加函数地址);//符号表中存的是函数名加函数名修饰规则生成的代码(把类型带进名字)
	                                      //C语言中存的是函数名,	区分不开
	func(1.2, 1);
	return 0;
}
运行结果:

(2)参数个数不同;

代码举例:
cpp 复制代码
void func(int a, double b)
{
	cout << "void func(int a, double b)" << endl;
}
void func(double a, int b,int c)//函数的地址是函数第一句指令的地址,只声明不定义的函数没有地址;
{
	cout << "void func(double a, int b,int c)" << endl;
}
int main()
{
	func(1, 1.2);//call func(加函数地址);//符号表中存的是函数名加函数名修饰规则生成的代码(把类型带进名字)
	                                      //C语言中存的是函数名,	区分不开
	func(1.2, 1,2);
	return 0;
}
运行结果:

(3)参数类型不同;

代码举例:
cpp 复制代码
void func(int a, int b)
{
	cout << "void func(int a, int b)" << endl;
}
void func(double a, int b)//函数的地址是函数第一句指令的地址,只声明不定义的函数没有地址;
{
	cout << "void func(double a, int b)" << endl;
}
int main()
{
	func(1, 1.2);//call func(加函数地址);//符号表中存的是函数名加函数名修饰规则生成的代码(把类型带进名字)
	                                      //C语言中存的是函数名,	区分不开
	func(1.2, 1);
	return 0;
}
运行结果:

2.函数重载原因;

C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载

代码举例:
运行结果:

由图所示,同名函数call的地址不一样,因为C++把参数也编进了函数地址,所以参数不同的同名函数地址不同。

四、引用;

1.简要介绍;

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。

代码举例:
cpp 复制代码
int main()
{
	int a = 10;
	int& b = a;//b是a的引用,b是a的别名;  &在类型和名的中间才是引用
	cout << a<<endl;
	cout << b << endl;
	cout << &a << endl;//a、b取的是一个变量
	cout << &b << endl;
	cout << ++a << endl;
	cout << ++b << endl;//引用可以替代传地址再解引用的情况;

	return 0;
}
运行结果:
结果分析:

b是a的别名,b改变a改变,a改变,b也改变;

2.引用的应用;

(1)传引用返回:

代码举例:
cpp 复制代码
int& count()//返回n的引用,
{
	int n = 0;
	n++;
	return n;//临时
}
int main()
{
	int ret = count();//这里打印的结果可能是1,也可能是随机值(取决于空间释放后是否置成随机值)
	cout << ret << endl;
	cout << ret << endl;
	return 0;
}
运行结果:
结果分析:

这里打印的结果可能是1,也可能是随机值;count返回的是count函数栈帧的一块空间,这部分的值取决于count栈帧结束后是否置为随机值;

(2)传引用传参:

代码举例:
cpp 复制代码
void swap(int& a, int& b)
{
	int tem = a;
	a = b;
	b = tem;
}
int main()
{
	int x = 1, y = 0;
	swap(x, y);
	cout << x << " "<<y << endl;//引用可以减少拷贝;
	return 0;
}
运行结果:
结果分析:

a是x的别名,b是y的别名;a、b的改变会影响x、y的值;

3.引用的限制条件;

1.必须再定义的地方初始化;
2.一个变量可以有多个引用;a的别名可以有 b、c、d,b的别名e,c的别名f;
3.引用一旦,就不能当别的变量的引用了,不能改变指向;

如果出了函数,对象还在就可以使用引用返回;否则不能使用引用返回;
传引用传参(任何时候):1.提高效率2.输出线参数(形参改变影响实参);
传引用返回(出了函数作用域对象还在):1.提高效率2.修改返回对象(例如returnsize);

4.权限问题;

简要介绍:

引用时发生类型转换 提升 截断 临时拷贝都会产生临时变量,要注意权限;(赋值不需要注意权限)。引用的权限一定要小于等于原变量的权限;

代码举例:
cpp 复制代码
int main()
{
	const int a = 10;//const 已经限定了;
	//权限的放大
	int& b = a;//这是权限的放大;引用的过程中权限可以平移,可以缩小,但是不能放大;
	//权限的平移
	const int& c = a;

	//权限的缩小;
	int x = 10;//x修改
	const int& y = x;//y不能修改,但是x的修改会影响y;

	//赋值不受权限的控制;

	const int q = 10;
	int p = q;赋值不受权限的控制;



	int a = 10;
	double d = a;//可以
	double& c = a;//不可以
	const double& q = a;//在c++里,发生类型转换赋值时候会产生临时变量,右边先赋给临时变量,临时变量再赋给左边
	//权限放大           //临时变量具有常性;
	return 0;
}
运行结果:
结果分析:

a是const,所以引用只能是权限平移,只能是const,b是放大,a是平移;x是int,所以引用可以是缩小、平移,不可放大;y是缩小;引用在发生类型转换的时候,会产生一个临时变量,这个临时变量是右值的临时拷贝,具有常属性,所以只能发生权限平移;c是权限放大,q是权限平移;注意,传参返回的是变量的临时拷贝,引用的时候也只能权限平移,记得加const;

五、内联函数;

1.简要介绍;

以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调 用建立栈帧的开销,内联函数提升程序运行的效率。

代码举例:
cpp 复制代码
inline int add(int x, int y)//调用时候不建立函数栈帧,而是把函数的内容直接替换到调用函数的位置;
{
	return (x + y);
}
int main()
{
	int m = add(1, 2);//在反汇编代码中没有调用函数;
	cout << m << endl;
	return 0;
}
运行结果:
结果分析:

由汇编代码得,函数调用得时候并没有call函数地址,即没有调用函数,而是直接把函数里得内容进行了运算;这就是inline函数,不会调用函数,而是直接展开;

2.常见问题;

代码举例:
cpp 复制代码
inline int func()
{
	int x1 = 0;
	int x2 = 0;
	int x3 = 0;
	int x4 = 0;

	int ret = 0;
	ret += x1;
	ret += x1;
	ret += x1;
	ret += x1;
	ret -= x1;
	ret -= x1;
	ret -= x1;
	ret -= x1;
	ret *= x1;
	ret *= x1;
	ret *= x1;
	ret *= x1;
	ret /= x1+1;
	ret /= x1+1;
	ret /= x1+1;
	ret /= x1+1;

	return ret;
}
int main()
{
	/*int m = add(1, 2);*/
	int m = func();//很复杂就不会按照内联函数算,还是会调用函数
	cout << m << endl;
	return 0;      //100行调用内敛函数(函数内容100行);全部展开 10000行;不展开(一行函数调用,一行call函数地址,共两百行)
运行结果:
结果分析:

内敛函数很复杂或者有递归,即使声明它是内联函数,也不会展开,而是去调用函数。

3.声明和定义;

inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。内联函数不生成指令(不生产函数地址,不进入符号表),在调用的地方展开;

4.优缺点:

内敛函数:

优点:1.没有宏的缺点;

缺点:内联函数很长会使程序变大(代码膨胀,安装包变大);因此:如果内联函数很大或者是递归,编译器会自动否认他是内联;

六、auto关键字;

1.简要介绍;

C++11中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一 个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。

代码举例:
cpp 复制代码
#include<vector>;
#include<string>;
int main()
{
	int a = 0;
	auto b = a;//b 是整形;//(自动推导);
	auto c = &a;//c 是指针;
	auto& d = a;//d 是引用;
	
	//auto普通场景没有价值,类型很长才有价值;
	std::vector<std::string> v;
	std::vector<std::string>::iterator it = v.begin();
	auto he = v.begin();//简化代码
	cout << typeid(b).name() << endl;
	cout << typeid(c).name() << endl;
	cout << typeid(d).name() << endl;//看类型
	cout << typeid(he).name() << endl;
	return 0;
}
运行结果:
结果分析:

auto可以根据右边的值自动判断变量类型,简化了变量名比较长时程序得复杂度;
1. auto不能作为函数的参数。
2. auto不能直接用来声明数组。

2.范围for;

代码举例:
cpp 复制代码
int main()
{
	int array[] = { 1,2,3,4,5,6 };//遍历数组;
	for (auto e : array)//依次取数组中的元素赋值给e,自动迭代,自动判断结束;(e改变 不影响数组的值)
	{//auto可以改为int,但是最好是auto;
		cout << e << " ";
	}
	cout << endl;
	for (auto& e : array)//依次取数组中的元素赋值给e,自动迭代,自动判断结束;(e改变 不影响数组的值)
	{//auto可以改为int,但是最好是auto;
		e*=2;
	}
	for (auto e : array)//依次取数组中的元素赋值给e,自动迭代,自动判断结束;(e改变 不影响数组的值)
	{//auto可以改为int,但是最好是auto;
		cout << e << " ";
	}

	//范围for针对的是数组名,函数传参传的是指针,不可以使用;
	cout << endl;
	return 0;
}
运行结果:
结果分析:

依次取数组中的元素赋值给e,自动迭代,自动判断结束;(如果e不是引用,e改变 不影响数组的值);范围for针对的是数组名,函数传参传的是指针,不可以使用范围for;

七、nullptr;

1.简要介绍;

在C++11中,NULL是0,默认为整形;如果要传一个空指针,可以是(int*)NULL,也可以直接nullptr;

代码举例:
cpp 复制代码
void f(int)
{
	cout <<"void f(int)"<< endl;
}
void f(int*)
{
	cout << "void f(int*)" << endl;
}
int main()
{
	f(0);
	f(NULL);//NULL直接定义成0,默认成整形;
	f((int*)NULL);
	f(nullptr);//nullptr 值是0,类型是int*;
	return 0;
}
运行结果:
相关推荐
Buleall4 分钟前
期末考学C
java·开发语言
重生之绝世牛码6 分钟前
Java设计模式 —— 【结构型模式】外观模式详解
java·大数据·开发语言·设计模式·设计原则·外观模式
小蜗牛慢慢爬行12 分钟前
有关异步场景的 10 大 Spring Boot 面试问题
java·开发语言·网络·spring boot·后端·spring·面试
荒古前18 分钟前
龟兔赛跑 PTA
c语言·算法
Colinnian21 分钟前
Codeforces Round 994 (Div. 2)-D题
算法·动态规划
Algorithm157622 分钟前
云原生相关的 Go 语言工程师技术路线(含博客网址导航)
开发语言·云原生·golang
用户00993831430127 分钟前
代码随想录算法训练营第十三天 | 二叉树part01
数据结构·算法
shinelord明31 分钟前
【再谈设计模式】享元模式~对象共享的优化妙手
开发语言·数据结构·算法·设计模式·软件工程
დ旧言~37 分钟前
专题八:背包问题
算法·leetcode·动态规划·推荐算法