C++初阶入门

C++语法

1、命名空间

  1. 在同一个作用域里面,不能有同名变量
  2. 为了解决这个C语言没有解决的问题,C++引入了 namespace 解决这个问题
  3. namespace hello { int rand = 0; int time = 0; }
  4. 第三条就是由 namespace 形成的 命名空间域 ,命名空间里不仅能定义变量,还能定义函数、类型等。
  5. 如果想要访问这个命名空间域就要用 域作用限定符‘ :: ’ ,用法见第六条
  6. printf("%d\n",hello::rand);
  7. 如果定义了两个同名的命名空间,那么编译器编译时会将两个同名命名空间合并
  8. 命名空间里面可以再嵌套命名空间
  9. 命名空间不影响变量的生命周期
  10. 不能在函数里定义命名空间,只能在全局范围里定义命名空间,且命名空间大多数都放在头文件中定义
  11. using namespace hello;把命名空间展开,相当于把这一层命名空间拿掉

我们常常会看到这样一句代码using namespace std;这句代码的意思是拿掉封C++库的命名空间

2、命名空间的用法

了解了命名空间之后,我们就要学习命名空间的运用,有以下代码,我们应该怎么使用他的命名空间呢?

namespace N
{
 int a = 10;
 int b = 20;
 int Add(int left, int right)
 {
 return left + right;
 }
 int Sub(int left, int right)
 {
 return left - right;
 }
}
int main()
{
 printf("%d\n", a); // 该语句编译出错,无法识别a
 return 0;
}
  1. 加命名空间名称及作用域限定符
int main()
{
 printf("%d\n", N::a);
 return 0; 
}
  1. 放出命名空间中部分常用的变量
using N::b;
int main()
{
 printf("%d\n", N::a);
 printf("%d\n", b);
 return 0; 
}
  1. 放出整个命名空间
using namespce N;
int main()
{
 printf("%d\n", N::a);
 printf("%d\n", b);
 Add(10, 20);
 return 0; 
}

3、C++的输入、输出

1、cin>> (流提取运算符) 相当于C语言的输入printf
2、cout<< (流插入运算符)相当于C语言的输出scanf

4、缺省 / 默认参数

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

2、缺省分为全缺省半缺省,半缺省必须从右往左缺省

//全缺省
void TestFunc(int a = 10, int b = 20, int c = 30)
{
 cout<<"a = "<<a<<endl;
 cout<<"b = "<<b<<endl;
 cout<<"c = "<<c<<endl;
}

半缺省

void TestFunc(int a, int b = 10, int c = 20)
{
 cout<<"a = "<<a<<endl;
 cout<<"b = "<<b<<endl;
 cout<<"c = "<<c<<endl;
}

3、缺省参数不能在声明和定义中同时出现,会产生歧义,只能在声明的时候给

5、函数重载

C++支持同名函数,有两个前提
1、要求参数名相同
2、参数不同:参数个数 / 类型 / 顺序(顺序指的是不同类型的形参的顺序),至少有一个不同
3、返回值类型不同不构成重载,因为使用的时候无法区分要调用的是谁
4、C++重载时会进行函数名修饰:_Z+函数名长度+函数名+类型首字母
5、extern "C"的作用是告诉编译器,extern "C"声明的函数,是C语言的库,要用C语言的方式去调用链接

6、编译链接的过程

1、预处理:头文件展开、宏替换、条件编译(ifdef 等)、去掉注释、生成test.i文件
2、编译:检查语法,生成汇编代码(有语法错误就是在这一步检查出来的)、生成test.s文件
3、汇编:把汇编代码转换成二进制的机器码、生成test.o文件
4、链接:找调用函数的地址,链接对应上,合并到一起、生成a.out文件

7、了解引用“ & ”

1、引用就是给一个变量取另外一个名字,不会开辟新的内存空间
2、引用的写法
3、引用必须在定义的时候初始化
4、引用一旦引用了一个实体,就不能再有其他实体
5、取别名原则:对原引用变量,读写权限只能缩小,不能放大

int main()
{
   int a = 10;
   int& b = a;//b就是a的另外一个名字

   //取别名原则:对原引用变量,权限只能缩小,不能放大
   const int x = 20;
   int&y = x;//权限放大
   const int&y = x;//权限不变
   
   int c = 10;
   const int&d = c;//权限缩小
   return 0;
}

6、const对引用的影响

int main()
{
   int a = 10;
   int& b = a;
   const int& c = 20;

   double d = 2.2;
   int f = d;//不同类型的赋值会发生隐式类型转化,产生临时变量,临时变量具有常性
   const int& e = d;//用const的修饰引用,表示此引用只有读权限没有写权限,权限不变
   //所以const int& e可以变成double类型的d的别名
   
   //这时候e不是d的别名,是 临时变量 的别名
   return 0;
}

7、引用的两个作用

1、引用的第一个作用就是做参数,可以在函数的形参位置使用引用,这样的好处是方便理解,同时也能提高代码的效率:下面是传值参数传引用参数效率的比较

  • 以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,需要浪费拷贝的效率,尤其是 当参数或者返回值类型非常大时,效率就更低。
  • 引用的第二个作用就是传引用返回,和传值返回相比,区别在于传值返回会有一个临时拷贝,而传引用返回,返回的是返回参数的别名(实际上就是直接返回参数),而不是拷贝
  • 注意:如果函数返回时,出了函数作用域,如果返回对象还没有还给系统,则可以使用传引用返回,如果已经还给系统,则必须使用传值返回,否则可能会出越界问题

8、指针与引用的区别

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

10、注:从语法层面而言引用是取别名,没有开额外空间,指针是存储地址,开了4/8byte的空间;但从底层来看,他们是用一样的方式实现的,他们直接的差别就像耐克鞋子和莆田鞋子一样,其实都是一个厂子里生产出来的,本质上鞋的模样和品质都是一样的,但是一个就是有牌子,另一个就是假鞋

9、内联函数

1、在反复使用的简短函数前面加上inline,就会使它变成内联函数
2、内联函数的作用是提高函数的使用效率,让函数能够直接展开,而不用反复构建函数栈帧,效果类似于宏
3、和宏定义相比,内联函数解决了宏函数晦涩难懂,容易写错的问题
4、内联函数比宏的优点更在于,内联函数支持调试,而宏不支持调试

  • inline是一种以空间换时间的做法,省去调用函数额开销。所以代码很长(一般超出10行)或者有循环/递归的函数不适宜使用作为内联函数
  • inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会忽略掉内联。
  • inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

10、宏定义的检测方法

1、验证自己的宏定义写的是否正确,最好的方法就是调用替换一下

#define ADD(X,Y) ((X)+(Y))
int main()
{
   //下面是几种常见的宏替换的场景
   ADD(1,2);//第一种
   if(ADD(1,2))//第二种
   {}

   ADD(1 & 2,3 | 4);//第三种
   ADD(1,2)*4;//第四种
}
  • 宏的优点:1、增强代码复用性;2、提高性能
  • 宏的缺点:1、不方便调试(因为预编译阶段进行了替换);2、导致代码可读性差,可维护性差,容易误用;3、没有类型安全检查
  • C++可以替代宏的技术:1、常量定义 换用const ;2、函数定义 换用内联函数

11、AUTO关键词

  • 使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换变量实际的类型
  • auto的意义之一:当类型很长时,懒得写,可以让auto自动推导
#include <iostream>
#include <map>
#include <string>
using namespace std;

int TestAuto()
{
	return 10;
}

int main()
{
	const int a = 10;
	auto b = &a;//auto b的类型是编译器推导的右边变量的类型(这个auto的类型是const int*)
	auto c = 'a';
	auto d = TestAuto();

	cout << typeid(c).name() << endl;//打印变量类型的函数typeid
    cout << typeid(d).name() << endl;
	return 0;
}
  • auto的意义之二:
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9};

TestFor(array);
for (int i = 0; i < sizeof(array) / sizeof(int); ++i)
{
    array[i] *= 2;
}

	for (int i = 0; i < sizeof(array) / sizeof(int); ++i)
	{
		cout << array[i] << " ";
	}
	cout << endl;

	//范围for循环
    // 依次自动取array中的数据,赋值给e,自动判断结束
	for (auto& e : array)//加上引用,此时e就是array的别名,可以直接修改到array的元素
	{
		e /= 2;
	}

	for (auto x : array)//范围for,效果与上面int写的for循环作用相同,可以遍历array数组
	{
		cout << x << " ";
	}
	cout << endl;

	return 0;
}
  • 注意:auto不能做函数的参数;不能直接定义变量,定义变量时必须初始化;不能直接用于声明数组
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值