赞
踩
目录
一,关键字(C++98)
二,命名空间
在C/C++,如大量变量、函数、类的名称都存在于全局作用域中,可能会导致很多冲突;使用命名空间(namespace)的目的就是对标识符的名称进行本地化,以避免命名冲突或名字污染;
std是C++ 标准库中命名空间的名称,其中包含了大部分标准库的函数和类,使用std命名空间来访问其中的类和函数;
命名空间定义
namespace + 命名空间名字 + { };
- //命名空间,N为命名空间名字
- namespace N
- {
- //可定义变量,也可定义函数
- int a;
- void fun() {};
- }
- //可嵌套
- namespace N
- {
- int a;
- void fun() {};
- namespace N
- {
- int a;
- void fun() {};
- }
- }
- //命名空间可相同,最后会合并
- namespace N
- {
- int a;
- void fun1() {};
- }
-
- namespace N
- {
- int b;
- void fun2() {};
- }
命名空间使用
- //命名空间名称+限定符
- int main()
- {
- N::a = 2;
- N::N::a = 2;
- return 0;
- }
- //using namespace + 命名空间名称
- using namespace N;
- int main()
- {
- a = 2;
- b = 2;
- return 0;
- }
- //using + 命名空间成员
- using N::a;
- int main()
- {
- a = 2;
- return 0;
- }
using关键字
- //声明类模板别名,不可在函数内使用
- template<typename T>
- using IntVector = std::vector<T>;
-
- //声明实例类(类型)别名
- using IntVector = std::vector<int>;
- //在类内部声明的别名
- template<class T>
- class A
- {
- public:
- using MyInt = int; //类内可以直接使用
- private:
- MyInt _i;
- T _var;
- };
-
- A<int>::MyInt var; //但在内外使用必须加上所属类作用域
三,C++输入/输出
- cout 标准输出(控制台);
- cin 标准输入(键盘);
- #include <iostream>
- int main()
- {
- std::cout << "hello world!" << std::endl;
- return 0;
- }
- //推荐此方式
- #include <iostream>
- using namespace std;
- int main()
- {
- cout << "hello world!" << endl;
- return 0;
- }
- //输入输出
- #include <iostream>
- using namespace std;
- int main()
- {
- int a, b;
- cin >> a >> b;
- cout << a << "/" << b << endl;
- return 0;
- }
注:
- 早期标准库没有在std命名空间中实现,只需包含.h的头文件即可,后来为了和C头文件区分及正确使用命名空间,规定头文件不带.h;
- 使用C++输入输出更方便,无需数据格式控制,自动识别类型,如%d/%c等,浮点数最多输出五位,但类似结构体的连续输出用printf更好;
四,缺省参数
- #include <iostream>
- using namespace std;
- void fun(int a = 0)
- {
- cout << a << endl;
- }
- int main()
- {
- fun();
- fun(10);
- return 0;
- }
分类
- //全缺省参数
- void fun(int a = 0, int b = 1, int c = 2)
- {
- cout << a << b << c << endl;
- }
- //半缺省参数
- void fun(int a , int b = 1, int c = 2)
- {
- cout << a << b << c << endl;
- }
注:
- 参数必须从右往左依次给出,不可间隔;
- 缺省参数不可在函数声明和定义中同时出现,如声明和定义缺省位置默认值不同,编译器无法确定默认值,即使默认值相同也不可,此时建议定义是不加默认值;
- 缺省值必须是常量或全局变量;
- C不支持;
- //支持全局变量
- int ab = 1212;
- void fun(int a = ab)
- {
- cout << a << endl;
- }
五,函数重载
函数重载是函数的一种特殊情况,C++允许同一个作用域中声明几个功能类似的同名函数,其形参列表(参数个数或类型或顺序)必须不同,常用来实现功能类似数据类型不同的问题;进而保持代码的可读性和维护性;
函数名相同,参数不同;即通过传递的参数不同,调用不同函数;
- //可根据参数不同调用不同函数
- int Add(int a, int b) { return a + b; }
- double Add(double a, double b) { return a + b; }
- int main()
- {
- Add(1, 2);
- Add(1.0, 2.0);
- return 0;
- }
名字修饰(name mangling)
运行程序时,需经历:预处理、编译、汇编、链接;在编译后链接前,如a.o目标文件中无Add函数的地址,地址在b.o文件中,链接器会到b.o符号表中查找地址,然后链接;链接时,依据名字(函数名修饰)查找,不同编译器修饰规则不同;如:g++函数名修饰规则,[_Z+函数长度+函数名+类型首字母];
注:(f.h/f.c/test.c)
extern "C"
在C++中有时候可能需要将某些函数按照C的风格来编译,在函数前加extern "C";即编译后的函数修饰名,可调用C库;C++编译器,既可识别C++函数名修饰规则,也可识别C的修饰规则(兼容C);如C的项目调用C++的库,可在C++库的函数前添加extern “c”即可;
- //按C编译
- extern "C" int Add(int a, int b) { return a + b; }
六,引用
类型 + & + 引用变量名(即别名) = 引用实体
- //引用变量
- int a = 10;
- int& ra = a;
- //引用变量
- int a = 10;
- int* pa = &a;
- int*& rpa = pa;
特性
int& ra; //此时会报错,必须初始化;
- //一个变量可以有多个引用(即多个别名)
- int a = 10;
- int& ra = a;
- int& rb = a;
- //引用一旦引用一个实体,再也不能引用其他实体(即不能同时引用两个实体)
- int a = 10;
- int b = 20;
- int& ra = a;
- int& ra = b;
常引用
- const int a = 10;
- //int& ra = a; //编译时会报错,因为a为常变量,且不可扩大读写权限
- const int& ra = a;
- //int& ra = 10; //编译时会报错,因为10为常量
- const int& ra = 10;
- //可缩小读写权限,但不可放大读写权限
- int a = 10;
- int& ra = a;
- const int& rb = a;
- //保护形参,避免误改
- void PrintStack(const ST& s);
- //即可传变量,也可传常量
- int Add(const int& a, const int& b)
- {
- return a + b;
- }
- int main()
- {
- int a = 10, b = 20;
- Add(a, b);
- Add(1, 2);
- return 0;
- }
- int a = 3.14;
- double b = a; //类型转换中间会产生一个临时变量
- //double& ra = a;
- const double& ra = a; //类型转换中间会产生一个临时变量,临时变量具有常性
使用场景
- //做参数
- //因为是实参的别名,实际交换的就是原本的参数变量,类似指针;
- void Swap(int& a, int& b)
- {
- int tmp = a;
- a = b;
- b = tmp;
- }
- //C语法
- void SListPushBack(SLTNode** phead, int x);
- //C++语法
- void SListPushBack(SLTNode*& phead, int x);
- //传值返回
- //c出作用域会销毁,编译器会生成一个临时变量,复制c的值
- //临时变量,如比较小通常再寄存器,如比较大会再main中开辟一块空间
- int Add(int a, int b)
- {
- int c = a + b;
- return c;
- }
-
- //传引用返回
- //临时引用,int& tmp=c;
- int& Add(int a, int b)
- {
- int c = a + b;
- return c;
- }
注:如函数返回时,出了函数作用域,返回对象还未还给系统,则可使用引用返回,如已还给系统,则必须传值返回;
传值/传引用效率对比
用值作为参数或返回值,效率低下,尤其是非常大时;
引用和指针的区别
在语法上,引用是别名无独立空间,和引用实体共用同一块空间;
在实现上,实际是有空间的,因为引用是按照指针方式实现的(汇编代码完全类似);
七,内联函数
以inline修饰的函数叫做内联函数,C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率;C语言是利用宏实现的;
特性
宏优点
- 增强代码复用性;
- 提高性能;
宏缺点
- 语法复杂,容易出错;
- 无类型安全检查;
- 无法调试和递归;
C++替代宏
八,auto关键字(C++11)
早期C/C++中,使用auto修饰的变量具有自动生命周期变量(多余,变量默认拥有自动的生命周期),但一直没有人去使用;C++11中,auto不在是一个存储类型标识符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时推导而得;
- 使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型;
- 因此auto并非是一种类型的声明,而是一个类型声明时的占位符,编译器在编译时会将auto替换为实际变量类型;
- //通过右边赋值对象,自动推导变量类型
- int a = 10;
- auto b = a;
-
- //定义变量时,必须初始化
- //auto b;
auto使用细则
- int a = 10;
- int& ra = a;
- auto b = a; //int
- //推导指针
- auto c = &a; //int*
- auto* cc = &a; //int*
- //推导引用
- auto d = ra; //int
- auto& dd = a; //int&
- //定义多个变量,必须是相同类型
- int a;string b;
- //auto c = a, d = b;
auto不能推导的场景
- //auto不能作为函数的参数
- void fun(auto a){}
- //auto不能直接用来声明数组
- auto arr[] = { 1,2,3 };
九,基于范围的for循环(C++11)
对于有范围的集合,有程序员来说明循环的范围是多余的,有时还会容易犯错误;因此C++11中引入基于范围的for循环;
语法:for( 用于迭代的变量 :被迭代的范围){ 循环体 }
- int main()
- {
- int arr[] = { 1,2,3 };
- for (auto& i : arr)
- {
- i = 1;
- }
- for (auto i : arr)
- {
- cout << i << endl;
- }
- return 0;
- }
注:与普通循环类似,可用continue来结束本次循环,或break来跳出整个循环;
范围for使用条件
十,指针空值nullptr(C++11)
空指针,不是内存不存在的指针,是内存为第一个字节的编号,一般不使用这个字节数据;空指针一般用来初始化,表示指针指向无效的空间;
C++98中的指针空值
- //C语言
- #define NULL ((void *)0)
-
- //一个指针没有合法的指向时,指定一个空值
- //把void*类型赋予p1,其实会隐式转换相应的类型
- int* p1 = NULL;
- int* p2 = 0;
C++11指针空值nullptr
C++为强类型,无法隐式转换,引入nullptr表示空指针;
优点:
- void f(int a){cout << "f(int)" << endl;}
- void f(int* a){cout << "f(int*)" << endl;}
- int main()
- {
- f(0); //f(int)
- f(NULL); //f(int)
- f((int*)NULL); //f(int*)
- f(nullptr); //f(int*)
- }
- #ifndef NULL
- #ifdef __cplusplus
- #define NULL 0
- #else
- #define NULL ((void *)0)
- #endif
- #endif
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。