前言
C++不是C#
C++兼容大部分C的东西,但不是完全(98%的样子,除非遇到了不兼容的,那就记一下,不然就认为自己在C里面写的那些可以写到C++里(不兼容编译器也会提醒))
C++标准库的头文件都没有.h,这些都需要std这个命名空间才能用;C的库在CPP上也能用(不会用一般),但是不需要std;比如cstdio要std stdio.h就不用
学完C++的继承和多态之后建议看一下《Effective C++》,然后C++ Primer可以当做是一本语法字典,
把C++全部学完之后还建议看一下STL源码剖析
第一本和第三本应该来说是要必看的,看和不看差别很大
命名空间
域
域的优先级:如果有指定访问哪个域的话,先是去这里面找,找不到就报错
没有指定访问的话才是局部域里面找,最后才是全局域
不同域里面可以定义相同的变量
展开命名空间域的话要看是在哪展开的,在全局展开就当全局变量用(但不是"真"全局变量),在局部展开就当局部变量用(eg:在全局展开,就不能跟全局变量重名,不然会报错)
注意:局部变量之间可能也是不同域,看局部是不是在同一局部
命名空间的展开和头文件的展开要区分一下:
头文件展开类似拷贝,命名空间展开类似拆墙来让他们可以访问这里
命名空间的用法
一般开发中是用项目名字做命名空间名
命名空间的性质:
1.命名空间中可以定义变量/函数/类型(比如结构体,typedef关键词)
2.命名空间可以嵌套
3.同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
(但是要注意会重名,可以用嵌套来解决)
命名空间的定义:
namespace renshen
{
}//注意,这里没有分号
嵌套:
namespace N1
{
int a;
int b;
int Add(int left, int right)
{
return left + right;
}
namespace N2
{
int a;
int b;
int Sub(int left, int right)
{
return left - right;
}
}
}
这种嵌套这的使用为: eg: N1::N2::a; N1::a;
命名空间的使用
1.全局展开命名空间
--建议项目里不要这么去展开,建议日常可以这么搞;项目建议要选择指定访问,不能轻易展开命名空间
eg: using namespace std;
2.部分展开命名空间--在实际中常把常用的展开
eg: using std:cout;
3.加命名空间名称及作用域限定符(::前面没有东西的话,默认是全局访问,先访问"真"全局变量)
--也就是指定访问
eg:N1::N2::a;
N1::a;
C++的输入和输出
<<是流插入运算符,>>是流提取运算符
用cin cout不方便的时候就去用printf,scanf;虽然cout也能控制输出格式,但是没必要,不用学;printf和cout的应用场景具体见蓝桥杯C++小结篇
缺省参数
应用:比如像给函数提供默认选项
分为两类:全缺省参数和半缺省参数
函数有声明的话,函数的缺省参数只能在声明中给出;如果没有声明的话,才能在定义中写
全缺省参数:
eg:void Func(int a = 10, int b = 20, int c = 30)
半缺省参数:(有至少一个没给默认值,有至少一个有默认值)
eg:void Func(int a, int b = 10, int c = 20)
缺省规则:参数的默认值必须要从右到左依次给出(也就是从左边开始空,还不能跳着空,要连续)
eg:void Func(int a, int b = 10, int c )--这样不行
在使用缺省参数的时候,对实参的要求:
从左到右必须依次给出(也就是从右边开始空,还不能跳着空,要连续)
不能eg:Func(1,,2);
函数有声明的话,函数的缺省参数只能在声明中给出 的原因:
1.避免声明和定义重复给缺省参数–害怕出现两个给的缺省参数不同的情况
2.因为声明一般被放在头文件中,而函数定义一般在源文件里面。在编译的时候,C++采用的是分离编译–编译器在编译每个源文件时仅能看到当前文件的内容 ,所以只有缺省参数放在声明里才行。
函数重载
函数重载就是让同名函数(一般功能类似)能够共存
函数重载的几种情况:(单单返回值不同的话不算函数重载)
--这里的举例的话就只展示函数头
1.参数类型不同
int Add(int left, int right) 和 double Add(double left, double right)
2.参数个数不同
void f() 和 void f(int a)
3.参数类型的顺序的不同(形参的名不同没啥用)
void f(int a, char b) 和 void f(char b, int a)
注意:void f(int a, char b) 和 void f(int b, char a)不算函数重载,这俩就是同一个函数
int f(int a, char b) 和 void f(double b, char a)算函数重载,就算返回值类型不一样
C语言不支持重载,但是CPP支持重载的原因:
1.编译链接过程:C语言的符号表里面对同名的函数时一样的,而C++不是
2.函数名修饰规则:重载的话C语言编译时就会报错,防止汇编时规则不支持(因为他不会把参数类型啥的带进来) 但是C++对函数名的修饰会把参数的类型啥的带进来
拓展一下编译链接的过程:
比如现在有三个文件 list.h list.cpp text.cpp
1.预处理:这个过程会进行头文件展开/宏替换/条件编译/去掉注释……
生成 list.i text.i
2.编译:这个过程会检查语法(包括歧义,比如:调用歧义),生成汇编代码
生成文件:list.s text.s
3.汇编:将汇编代码转换成2二进制机器码(通过符号表-里面存的是函数名和地址的映射关系,具体啥样要看编译器)
生成文件:list.o text.o
4.链接:(在这一步,list.cpp和text.cpp才会"会师")
生成可执行程序: xxx.exe/a.out()//Linux不指定的话就会生成a.out()
对函数来说,如果有声明的话,声明就相当于是承诺(只要代码跟声明是匹配的就行)在链接那个过程才需要找定义
(该文件只有声明,没有对应的那个定义的才有此)
auto关键字(C++11)
auto用来自动推导出变量的类型
应用:很长的类型eg:迭代器 范围for等
auto的使用规则:
1.用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
比如: int a = 1; auto& x = a;
2.在同一行(以;划时)定义多个变量时不能用auto
比如: auto a,b;
3.auto不能用在函数形参和返回值上,但是C++14可以做返回值了
4.auto不能用来声明数组
eg: auto a[2] = {0,1};//不能这样
引申出一个点:(知道有这个东西就行了)
求变量类型的方法:typeid().name()
eg:
auto d = 2+3.14;
cout<<typeid(d).name()<<endl;
范围for
适用范围:数组和容器
它依次取其中的数据赋值给e(变量名不是e也行)–注意是赋值!还会自动迭代,自动判断结束
使用条件:for循环迭代的范围是必须确定的
举反例: void over(int arr[]) { for(auto& e : arr) { …………………… } } 补充:数组在传参成为形参之后,其实就是指针了,就算改成arr[5]也一样
举例:
for(auto e:arr)
{
………………
}
当然,如果………………只是一条语句的话,就不用{}了
要是想修改数组或者容器里面的数据的话要用到引用:
for(auto& e:arr)
{
……………………
}