C++入门
- 前言
- 1. C++关键字(C++98)
- 2. 命名空间
- 2.1 命名空间定义
- 2.2 命名空间使用
- 2.3嵌套命名空间
- 3. C++输入&输出
- 4. 缺省参数
- 4.1 缺省参数概念
- 4.2 缺省参数分类
- 5. 函数重载
- 5.1 函数重载概念
- 5.2 C++支持函数重载的原理--名字修饰(name Mangling)
- 6. 引用
- 6.1 引用概念
- 6.2 引用特性
- 6.3 常引用
- 6.4 使用场景
- 6.5 传值、传引用效率比较
- 6.6 引用和指针的区别
- 7. 内联函数
- 7.1 概念
- 7.2 特性
- 8. auto关键字(C++11)
- 8.1 auto简介
- 8.2 auto的使用细则
- 8.3auto不能推导的场景
- 9. 基于范围的for循环(C++11)
- 9.1 范围for的语法
- 9.2 范围for的使用条件
- 10. 指针空值nullptr(C++11)
- 10.1 C++98中的指针空值
前言
C++是在C的基础之上,容纳进去了面向对象编程思想,并增加了许多有用的库,以及编程范式等。熟悉C语言之后,对C++学习有一定的帮助,本章节主要目标:
- 补充C语言语法的不足,以及C++是如何对C语言设计不合理的地方进行优化的,比如:作用域方面、IO方面、函数方面、指针方面、宏方面等。
- 为后续类和对象学习打基础。
1. C++关键字(C++98)
C++总计63个关键字,C语言32个关键字
2. 命名空间
在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。
#include #include int rand = 10; int main() { printf("%d\n", rand); return 0; }
rand是一个库函数,所以不能使用rand做变量名称,会出现以下错误
C语言没办法解决类似这样的命名冲突问题,所以C++提出了namespace来解决
2.1 命名空间定义
定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员。只要是能出现在全局作用域中的声明就能置于命名空间内,主要包括:类、变量(及其初始化操作)、函数(及其定义)、模板和其他命名空间(这意味着命名空间可以嵌套):
namespace green//命名空间的名字 { //定义变量 int rand = 10; //定义函数 int Add(int left, int right) { return left + right; } //定义类型 struct Node { struct Node* next; int val; }; //嵌套命名空间 namespace green { int c; int d; int Sub(int left, int right) { return left - right; } } }
同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。命名空间可以是不连续的。命名空间既可以定义在全局作用域内,也可以定义在其他命名空间中,但是不能定义在函数或类的内部。
注意:一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中。因为不同命名空间的作用域不同,所以在不同命名空间内可以有相同名字的成员。
定义在某个命名空间中的名字可以被该命名空间内的其他成员直接访问,也可以被这些成员内嵌作用域中的任何单位访问。位于该命名空间之外的代码则必须通过域作用限定符::明确指出所用的名字属于哪个命名空间。
namespace green { int a = 10; } int a = 30; int main() { int a = 20; printf("%d\n", a); printf("%d\n", ::a); printf("%d\n", green::a); return 0; }
上面的代码在局部域、全局域、green命名空间域中分别定义了一个a变量并且赋了不同的值,在没指定作用域的时候,会根据局部优先的原则去访问局部变量;::a的左边什么也没有意味着去全局域中查找;green::a则指定了要到green这个域里面去查找。
2.2 命名空间使用
命名空间中成员该如何使用呢?比如:
namespace green { int a = 0; int b = 1; int Add(int left, int right) { return left + right; } struct Node { struct Node* next; int val; }; } int main() { printf("%d\n", a); return 0; }
命名空间的使用有三种方式:
- 加命名空间名称及作用域限定符:
int main() { printf("%d\n", green::a); return 0; }
- 使用using将命名空间中某个成员引入:
using green::b; int main() { printf("%d\n", green::a); printf("%d\n", b); return 0; }
- 使用using namespace 命名空间名称 引入
可以用using namespace green将命名空间展开,把命名空间中的成员提升到包含命名空间本身和using指示最近的作用域
namespace green { int a = 10; int b = 5; int c = 100; } int a = 30; using namespace green; int main() { printf("%d\n", a);//a不明确,出现二义性 printf("%d\n", ::a);//正确:访问全局的a printf("%d\n", green::a);//正确:访问green中的a printf("%d\n", b);//正确,去访问green中的b int c = 79;//当前局部变量的c隐藏了green::c c++;//当前局部的c设置成80 return 0; }
以上面的代码为例,通过using把green命名空间展开,这个过程相当于把green中的名字“添加”到全局作用域中,这使得程序可以直接访问green中的所有名字。
当命名空间被注入到它的外层作用域之后,很可能该命名空间中定义的名字会与其外层作用域中的成员冲突。例如在主函数中,green的成员a就与全局作用域中的a产生了冲突。这种冲突是允许存在的,但是要想使用冲突的名字,我们就必须明确指出名字的版本。main函数中所有未加限定的a都会产生二义性错误。
为了使用像a这样的名字,我们必须使用作用域运算符来明确指出所需的版本。我们使用::a来表示全局作用域中的a,而使用green::a来表示定义在green中的a。
因为main的作用域和命名空间的作用域不同,所以main内部的声明可以隐藏命名空间中的某些成员的名字。例如,局部变量c隐藏了命名空间的成员green::c。在main中使用c不存在二义性,他指的就是局部变量c。
2.3嵌套命名空间
namespace green { int a = 10; namespace green1 { int a = 900;//将外层作用域的a隐藏了 int d = 1000; } //int b = d;//不正确:d是未声明的标识符 int b = green1::d;//正确访问的是green1里面的d namespace green2 { int f = green1::d;//正确 } } int main() { printf("%d\n", green::green2::f); printf("%d\n", green::green1::a); printf("%d\n", green::a); return 0; }
3. C++输入&输出
新生婴儿会以自己独特的方式向这个崭新的世界打招呼,C++刚出来后,也算是一个新事物,那C++是否也应该向这个美好的世界来声问候呢?我们来看下C++是如何来实现问候的。
#include // std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中 using namespace std; int main() { cout >和 int a; double b; char c; // 可以自动识别变量的类型 cin > a; cin >> b >> c; cout cout Func(); // 没有传参时,使用参数的默认值 Func(10); // 传参时,使用指定的实参 return 0; } cout Func(); Func(1); Func(1, 2); Func(1, 2, 3); return 0; } cout //Func();//函数调用参数太少 Func(1); Func(1, 2); Func(1, 2, 3); return 0; } cout cout Add(1, 2); Add(1.1, 2.2); return 0; } cout cout f(); f(1); return 0; } cout cout f(10, 'a'); f('a', 10); return 0; } cout cout //f();不传参数的时候调用存在二义性 f(1); return 0; } int a = 0; int& b = a;//定义引用类型,b是a的引用 int& c = a; return 0; int a = 0; int& b = a; int& c = a; cout int a = 10; int& d;//不能这样 return 0; } int a = 10; int& b = a; int& c = a; return 0; } int a = 80; int num = 888; int& b = a; int& c = a; b = num;//这里是把num的值赋给a,并不是让b变成num的引用 cout const int a = 10; int b = a;//可以,值的拷贝 int& b = a;//权限放大 return 0; } const int a = 10; const int& b = a;//权限平移 return 0; } // 权限可以缩小 int c = 20; const int& d = c; } int a = 99; return a; } int main() { //int& ret = Text();//函数返回会创建临时变量 const int& ret = Text();//用引用接收必须要加const修饰 return 0; } double a = 3.14; //int& b = a;//错误的类型转换,产生临时变量 const int& b = a;//正确 return 0; } cout cout //Text1(1 + 3);//错误 Text(1 + 3);//正确 return 0; } int tmp = num1; num1 = num2; num2 = tmp; } int main() { int a = 10; int b = 11; cout int* tmp = p1; p1 = p2; p2 = tmp; } int main() { int a = 10; int b = 11; int* pa = &a; int* pb = &b; cout int sum = x + y; return sum; } int main() { int a = 5; int b = 4; int ret = add(a, b); return 0; } static int a = 10; return a; } int main() { int ret = Text(); return 0; } int sum = x + y; return sum; } int main() { int a = 5; int b = 4; int ret = add(a, b); cout int sum = x + y; return sum; } int main() { int a = 5; int b = 4; int& ret = add(a, b); cout int a[100000]; }; void TestFunc1(A a) { ; } void TestFunc2(A& a) { ; } void TestFunc3(A* a) { ; } //引用传参————可以提高效率(大对象或者深拷贝的类对象) void TestRefAndValue() { A a; // 以值作为函数参数 size_t begin1 = clock(); for (size_t i = 0; i
- 使用using namespace 命名空间名称 引入
- 使用using将命名空间中某个成员引入:
- 10.1 C++98中的指针空值
还没有评论,来说两句吧...