文章目录
知识点 0:命名空间
为了避免工作中模块化工作所造成的函数名,变量名的命名冲突,引入命名空间概念,在此命名空间内的所有内容生命周期都只局限于该命名空间之中,不会和其他变量或函数造成同名冲突。
namespace Zone {//Zone 为命名空间的名称,相同命名空间会自动合成同一个空间(同名空间中不允许出现重复定义)
//可以定义变量,函数等
int a;
namespace Zone1{
//可以嵌套定义
int b;
}
}
最为推荐的命名空间元素使用方式:Zone ::a
或Zone::Zone1::b
知识点 1:标准输出输入
编写C++程序标准输入输出所需要包含的头文件
#include <iostream>
using namespace std;
//标准输入输出格式
输入:cin>>b>>a;
输出:cout<<a<<b<<endl; (endl为换行符)
//支持连续输入输出
其中字符串和非字符串输出是有本质区别的:非字符串指针输出首地址,字符串指针输出字符串内容
int a = 10 ;
char* p = "1234";
int* pa = &a;
std::cout << pa << std::endl; //非字符串指针输出地址
std::cout << p << std::endl; //字符串指针输出内容
知识点 2:缺省参数
如果没有指定实参时,采用默认参数值的一种。
- 全缺省参数
void TestFunc(int a = 10, int b = 20, int c = 30)
- 半缺省参数
void TestFunc(int a, int b = 10, int c = 20)
因为参数的接受顺序时从左向右,因此半缺省参数必须从右往左依次给出,不能存在间隔;缺省的参数不能在函数和定义中重复出现,编译器无法确定到底使用那个缺省值。
知识点 3:函数重载
同名函数的形参列表(参数个数,类型,顺序)必须不同,仅仅是返回值不同不能够构成函数重载。
int Add(int a = 1, int b = 2);
float Add(float a, float b);
int Add(int a, int b ,int c);
int Add(char a, char b) ;
int Add(int a, char b);
int Add(char a, int b)
让编译器按照C语言编译规则来进行编译
extern "C" {
int sub(int a, int b);
int mul(int a, int b);
}
- 为何C++支持函数重载,而C语言不支持函数重载
- C语言编译后,函数名修饰没发生任何改变,因此不论参数,类型发生任何改变,都是同一个函数,不会发生重载。
- C++编译时,编译器会讲函数参数类型等具体信息添加到函数名中。
- 换言之,C语言编译后同名函数无法进行区分,而C++时通过函数修饰规则来进行区分,即使同名函数调用时底层函数也是不同。
- C和C++编译的本质
知识点 4:引用
对已经存在的变量取一个别名,称之为引用(不会开辟内存空间,使用同一块内存空间,大小名的区别)——引用的效率是要高于正常传参的效率的。
- 标准化引用
int a = 10;
int& ra=a;//引用 引用必须初始化
// int& ra; 这是错误的;
ra =100;// 赋值 引用定义后不会改变实体的指向,因此会将原有内容全部改为100
- const类型的引用
const int a= 10;
const int& ra =a;//const类型必须用const类型来进行引用 且不能够被修改
int& rb =10; //这是错误的,b为常量不能进行引用
const int& rb =10;
double d =2.0 ;
double& rb =d;//引用类型必须和实体类型同类
int c=d;
const int& rd = d;//隐式类型转换,所生成的是一个临时整型变量,因此rd指向临时变量,具备常量特性不能够修改
- 引用作返回值
引用作返回值时,必须注意的是返回变量的生命周期一定要大于函数的生命周期
int& Add2(int a) {//函数结束,a已进行销毁,无法进行引用
return ++a;
}
void Test3() {
int a = 0;
int& d= Add2(a);//无法完成 ,因为a在函数结束时候已经销毁,因此出现访问越界的问题
cout << d << endl;
}
引用和指针的区别:
语法上:引用是一个别名,没有独立的空间,和其引用实体共用同一块空间
底层实现上:是有空间的,因为引用按照指针方式来进行实现的
- 引用在定义时必须初始化,而指针没有要求
- 引用再引用一个实体后,就不能在引用其他实体,而指针可以随意指向任何一个同类型实体
- 没有NULL引用,但有NULL指针
- sizeof含义不同,引用结果为引用类型大小,而指针始终时地址空间所占字节个数
- 引用自加即引用实体增加1,指针自加则表示指针向后偏移一个类型大小
- 存在多级指针,但没多级引用
- 访问实体方式不同,指针需要显示解引用,引用编辑器会自己处理
- 引用比指针用起来更加的安全
知识点 5:内联函数
编译时会将函数指令展开,不产生站真的开销,有效的提高代码的效率,可以代替宏函数的使用。(当然,内联函数只是一个建议,编译器会根据程序的实际情况来进行判断,如果代码简单则直接展开,否则会按照函数运行)
inline int Add(int a, int b)
{
return a + b;
}
知识点 6:auto自动类型
自动进行类型推导,相当于类型的占位符,不代表任何具体类型的存在,具体的类型会在编译时进行推导得到。
auto b = 2;
auto f = 3.0;
auto c = 'a';
auto d = 'a' + 'b';
cout << typeid(b).name() << endl;//整型
cout << typeid(f).name() << endl;//浮点型
cout << typeid(c).name() << endl;//字符型
cout << typeid(d).name() << endl;//整型也可能是字符型
- auto定义的变量必须初始化,且可以定义多个定义
- 定义多个变量,每一个表达式类型要一致
- 对于长类型变量定义使用更加简单
- 定义引用类型必须
auto& ra =b;
- 函数参数类型和数组不能够使用auto
知识点 7:范围for
对于数据范围确定的数据来说,可以使用范围for来进行(范围不确定一定不能使用范围for)
int array[]={1,2,3,4,5,6};
for(auto e: array)
cout<<e<<" ";
知识点 7+:nullptr
(NULL拥有二义性,指针空指和整型0)NULL在编译时会被默认为整型0,而不是我们所谓的空指针;而nullptr时指针空指,建议用nullptr表示指针控制,意义更加的明确。
int* p=NULL; 等价于 int* p=0;
nullptr类型: nullptr_t
nullptr可以隐式转换成任意指针类型(内置和自定义)
nullptr: 指针空值, 建议用nullptr表示指针空值,意义明确