C++:基础知识

1.C++关键字

C++总计63个关键字,C语言32个关键字

2.命名空间

在C++中,变量、函数和类都是大量存在的,这些变量、函数和类都将存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。
1.命名空间中可以定义变量/函数/类型。
2.命名空间可以嵌套。
3.同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成一个命名空间中。
4.命名空间的使用:
   ---加命名空间名称及作用域限定符 N::a
   ---使用using将命名空间中某个成员引入 using N::a
   ---使用using namespace命名空间名称引入 using namespace N

3.输入&输出

1. 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件
以及按命名空间使用方法使用std。
2. cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,他们都包含在包含<
iostream >头文件中。
3. <<是流插入运算符,>>是流提取运算符。
4. 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。
C++的输入输出可以自动识别变量类型。
5. 实际上cout和cin分别是ostream和istream类型的对象,>>和<<也涉及运算符重载等知识。

#include<iostream>
// std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中
using namespace std;
int main()
{
cout<<"Hello world!!!"<<endl;
return 0;
}

4.缺省参数

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

//全缺省
void Func1(int a = 0, int b = 0)
{
	cout << a << endl;
}
//半缺省 必须从右往左缺省且连续
void Func2(int a,int b = 0)
{
	cout << a << endl;
}
int main()
{//传参时必须从左往右
	Func1();
	Func2(1);
	Func2(1,2);
}

5.函数的重载 

在C++中,允许在同一个作用域中定义相同函数名的函数。但是参数顺序、参数个数、参数类型至少满足其中一种类型不同。返回值可以相同也可以不同,但只有返回值不同的话不能构成重
---C++如何支持函数重载的?为什么C语言不支持?
C/C++文件执行过程:
1、预处理:展开头文件/宏替换/条件编译(选择要运行的代码段)/去掉注释,生成test.i、list.i文件
2、编译:检查语法,生成汇编代码存到文件test.s、list.s(在这一步产生编译错误)
3、汇编:cpu看不懂汇编代码,在这一步要将汇编代码转成二进制机器码,产生test.o、list.o文件 汇编产生字段 将啥啥字(函数名、变量名)以块的形式处理
4、链接:将目标文件test.c和list.c链接到一起生成可执行文件
在链接的这一步,test.o中声明的存在在list.o的函数,分别将函数的地址存储到各自的符号表中,此时链接合并的时候就要找test.o运行文件中已声明但存在在list.o中函数的地址,这点C和C++有区别,在符号表中C语言直接存储函数名,而C++的函数名修饰规则会给函数名缀上参数类型首字母;(在Linux下)比如:int add( double a, int b, int* c)根据函数名修饰规则就会存成<_Z3adddipi>,所以在函数名相同时参数不同在C++中不会重名,在C语言中就会重名编译过不去就会报错。
---如何在C++的静态库/动态库中兼容运行C++/C语言的程序?
静态库/动态库中存储着编译成二进制代码的文件,没有可执行程序,它提供一些可供调用的内容。举例:如果C程序要在C++库中调用 void* tcmalloc(size_t n)这个函数,在链接过程中,test.o中是用tcmlloc去找函数的地址(call tcmalloc(?)),如果是C++程序就是(call _Z8tcmalloc(?));库中的符号表的命名规则是按照C++,此时在链接C程序时就会找不到,所以需要在声明前用extern声明一下是C的外部文件:extern "C" void* tcmalloc(size_t n)[在头文件声明],此时C++程序和C程序包含了头文件都能找到符号表中该函数的地址,因为C++程序兼容C所以也能遵守C的规则,而C不了解C++的命名规则;但此时这个函数也不支持重载了。

6.引用

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

int main()
{
	int a = 1;
	int& ra = a;//ra是a的引用,给a取了一个别名ra,变量空间取别名
}

引用的特性:
1.引用必须在定义的时候初始化
2.一个变量可以有多个引用
3.  引用一旦有了实体,就不能再引用别的变量

int main()
{
	const int a = 0;
	//int& b = a;
	//b的类型是int,编译不通过;a是只读,b的类型是int,也就是可读可写
	const int& b = a;
	int c = 1;//c可读可写
	const int& e = c;//e只读,引用命名时权限可以缩小但不能放大。
	int i = 0;
	double db = i;//隐式类型转换 先中间产生double类型的临时变量,
	const double& rd = i;//临时变量具有常性是只读的,所以必须要用const来修饰
	return 0;
}

----指针也是如此,存在权限的放大和缩小。

int a = 0;
int c = 0;
const int* cp1 = &a;//此时const修饰的是*cp1   *cp1的值不能发生改变
//int* p1 = cp1;//错误 *p1的值可以发生改变,违背了*cp1
int* p2 = &c;
const int* cp2 = p2;//可以,属于权限的缩小

----引用 作函数的形参 

void swap_cpp(int& r1, int& r2)//r1,r2是a,b的别名
{//"&"在类型名之后就是引用
	int tmp = r1;
	r1 = r2;
	r2 = tmp;
}
int main()
{
	int a = 0, b = 0;
	swap_cpp(a, b);
}

----引用 作函数返回值。引用作返回值时,该局部变量不是static时,出了函数会被销毁,下次调用函数重新创建运算时,原来的引用的值也会随之改变,也可能会变成随机值,不安全;如果是static静态变量,出了函数但不会被销毁,就可以引用返回,引用返回会少创建一个临时变量,提高代码效率。但是static定义变量时,定义语句只会在第一次调用时执行,加上给静态变量赋值的语句可以在每次调用时重新赋值,但是引用创建的变量的内容也会随之改变,但它是安全的,虽然变量改变但这块内容没有被销毁,不会出现随机值。
引用作函数参数(输出型参数)和函数返回值都可以提高程序运行的效率。

int Count1()
{
	static int n = 0;
	n++;
	return n;//返回的是新创的空间对n的临时拷贝
}
int& Count2()
{
	static int n = 0;
	n++;
	return n;//返回的还是n这个空间 不过是别名
}
int main()
{//函数传返回值都会产生拷贝,传引用不是拷贝返回,而是返回别名本质上就是返回原变量
	const int& r1 = Count1();
	//int& r1 = Count1();
	//Count1的返回值是临时变量,临时变量具有常性是只读的,给到int是可读可写的所以编译不通过
	int& r2 = Count2();
	//返回的就是n的别名 可读可写,此时r2就是n的别名
}//凡是临时变量都具有常性

----指针和引用的区别
1. 引用概念上定义一个变量的别名,指针存储一个变量地址。
2. 引用在定义时必须初始化,指针没有要求
3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何
一个同类型实体
4. 没有NULL引用,但有NULL指针
5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32
位平台下占4个字节)
6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
7. 有多级指针,但是没有多级引用
8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
9. 引用比指针使用起来相对更安全 

7.内联函数

void Swap(int& x1, int& x2)
{
	int tmp = x1;
	x1 = x2;
	x2 = tmp;
}

以Swap函数为例,如果要多次调用Swap函数栈帧的消耗会降低效率。C语言用宏函数处理来提高效率,宏函数有很多缺点。C++可以用内联函数来提高效率,每次调用函数的时候直接展开,不会进行函数压栈操作,用空间换取时间效率(每次调用都要展开)。
一般内联适用于小函数,小于大概20行。其次递归或者较长的函数都不适合内联。inline对于编译器只是一个建议,如果函数中有递归或者代码比较长,编译器会忽略内联请求。内联函数没有地址,在调用的时候直接展开。
由于宏 不方便调试,代码可读性差可维护性差,没有类型安全的检查。所以在C++中要对宏进行替代。#define N 10 替代为 const N = 10;宏函数则用内联函数替代。

8.auto关键字

int a = 0;
auto b = a;//根据a推出b的类型
int& c = a;
auto& d = a;
auto f = &a;
cout << typeid(a).name() << endl;//打印出a的类型名
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;
cout << typeid(d).name() << endl;
cout << typeid(f).name() << endl;//int*

auto不能作参数、auto不能来声明数组、不同的变量auto不能一起定义。

for (auto e : array)
{
	e *= 2;
}//将数组array中的每一个数据乘以2倍

当array数组传参给函数形参的时候,在函数中不能这样用,因为数组在函数中会退化成指针。

9.指针空值nullptr

void fun(int x)
{
	cout << "整型" << endl;
}
void fun(int* p)
{
	cout << "整型指针" << endl;
}
int main()
{
	int* pa = NULL;
	int* p2 = nullptr;//空指针
	fun(0);//输出 整型
	fun(NULL);//输出 整型。在C++中将NULL定义成0
	fun(nullptr);//输出 整形指针。空指针
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值