Re:从零开始的C++世界——(一)入门基础
文章目录
- C++发展历史
- 1.命名空间
- 1.1 namespace的价值
- 1.2 namespace的定义
- 1.3 命名空间使⽤
- 2.C++输⼊&输出
- 3.缺省参数
- 3.1 缺省参数的概念
- 3.2 缺省参数的分类
- 4.函数重载
- 5.引⽤
- 5.1引⽤的概念和定义
- 5.2 引⽤的特性
- 5.3 const引⽤
- 5.4 使用场景
- 5.5 指针和引⽤的关系
- 6.内联函数
- 6.1内联函数概念
- 6.2 内敛函数的特性
- 7.指针空值nullptr
- 7.1 C++98中的指针空值
- 7.2 C++11中的指针空值
- 8 **总结**
C++发展历史
C++的起源可以追溯到1979年,当时Bjarne Stroustrup(本贾尼·斯特劳斯特卢普,这个翻译的名字不同的地⽅可能有差异)在⻉尔实验室从事计算机科学和软件⼯程的研究⼯作。⾯对项⽬中复杂的软件开发任务,特别是模拟和操作系统的开发⼯作,他感受到了现有语⾔(如C语⾔)在表达能⼒、可维护性和可扩展性⽅⾯的不⾜。
1983年,Bjarne Stroustrup在C语⾔的基础上添加了⾯向对象编程的特性,设计出了C++语⾔的雏形,此时的C++已经有了类、封装、继承等核⼼概念,为后来的⾯向对象编程奠定了基础。这⼀年该语⾔被正式命名为C++。
语言的发展是一个初步递进、由浅入深的过程。
目前,C++还在不断向后发展中。
1.命名空间
1.1 namespace的价值
在C/C++中,变量、函数和后⾯要学到的类都是⼤量存在的,这些变量、函数和类的名称将都存在于全局作⽤域中,可能会导致很多冲突。使⽤命名空间的⽬的是对标识符的名称进⾏本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。
c语⾔项⽬类似下⾯程序这样的命名冲突是普遍存在的问题,C++引⼊namespace就是为了更好的解决这样的问题。
#include #include int rand = 10; int main() { // 编译报错:error C2365: “rand”: 重定义;以前的定义是“函数” printf("%d\n", rand); return 0; }
1.2 namespace的定义
• 定义命名空间,需要使⽤到namespace关键字,后⾯跟命名空间的名字,然后接⼀对{}即可,{}中即为命名空间的成员。命名空间中可以定义变量/函数/类型等。
// 普通的命名空间 namespace N1 // N1为命名空间的名称 { // 命名空间中的内容,既可以定义变量,也可以定义函数 int a; int Add(int x, int y) { return x + y; } }
• namespace只能定义在全局,当然他还可以嵌套定义。
// 命名空间可以嵌套 namespace N1 // 定义一个名为N1的命名空间 { int a; int b; namespace N2 // 嵌套定义另一个名为N2的命名空间 { int c; int d; } }
•项⽬⼯程中多⽂件中定义的同名namespace会认为是⼀个namespace,不会冲突。
// 定义一个N1 namespace N1 { int a; int Add(int x, int y) { return x + y; } } // 再定义一个N1 namespace N1 { int Mul(int left, int right) { return left * right; } }
其它特征:
• namespace本质是定义出⼀个域,这个域跟全局域各⾃独⽴,不同的域可以定义同名变量,所以下
⾯的rand不在冲突了。
• C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找⼀个变量/函数/
类型出处(声明或定义)的逻辑,所有有了域隔离,名字冲突就解决了。局部域和全局域除了会影响
编译查找逻辑,还会影响变量的⽣命周期,命名空间域和类域不影响变量⽣命周期。
• C++标准库都放在⼀个叫std(standard)的命名空间中。
1.3 命名空间使⽤
编译查找⼀个变量的声明/定义时,默认只会在局部或者全局查找,不会到命名空间⾥⾯去查找。所以下⾯程序会编译报错。
#include namespace bit { int a = 0; int b = 1; } int main() { // 编译报错:error C2065: “a”: 未声明的标识符 printf("%d\n", a); return 0; }
所以我们要使⽤命名空间中定义的变量/函数,有三种⽅式:
(1)加命名空间名称及作用域限定符,项⽬中推荐这种⽅式。
符号 :: 在 C++中叫做作用域限定符。
我们通过 命名空间名称 :: 命名空间成员 便可以访问到命名空间中相应的成员。
#include // 加命名空间名称及作用域限定符 namespace N { int a; float b; } int main() { N::a = 10; // 将命名空间中的成员a赋值为10 N::b = 5.55; // 将成员b赋值为5.55 printf("%d\n", N::a); // 打印a printf("%.2f\n", N::b); // 打印b return 0; }
(2)使用 using 将命名空间中成员引入
我们还可以通过 using 命名空间名称::命名空间成员 的方式将命名空间中指定的成员引入。
这样语句之后的代码中就可以直接使用引入的成员变量了。项⽬中经常访问的不存在冲突的成员推荐这种⽅式。
#include // 使用using将命名空间中的成员引入 namespace N { int a; float b; } using N::a; // 将命名空间中的成员a引入 using N::b; // 再将b引入 int main() { a = 10; // 将命名空间中的成员a赋值为10 b = 5.55; // 将b赋值为5.55 printf("%d\n", a); // 打印成员a printf("%.2f\n", b); // 打印成员b return 0; }
(3) 使用 using namespace 命名空间名称引入
最后一种方式就是通 using namespace 命名空间名称 将命名空间中的全部成员引入。
这样语句之后的代码中就可以直接使用该命名空间内的全部成员了,项⽬不推荐,冲突⻛险很⼤,⽇常⼩练习程序为了⽅便推荐使⽤。
#include // 使用 using namespace 命名空间名称引入 namespace N { int a; float b; } using namespace N; // 将命名空间N的所有成员引入 int main() { a = 10; // 将命名空间中的成员a赋值为10 printf("%d\n", a); // 打印命名空间中的成员a return 0; }
2.C++输⼊&输出
在学习任何语言的时候,我们首先会向 世界问好!也就是会在屏幕上打印 hello world!
那么用 C++ 如何打印呢?很简单。
#include using namespace std; int main() { cout // 在io需求⽐较⾼的地⽅,如部分⼤量输⼊的竞赛题中,加上以下3⾏代码 // 可以提⾼C++IO效率 ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); return 0; } cout Func(); // 没有传参时,使⽤参数的默认值 Func(10); // 传参时,使⽤指定的实参 return 0; } cout Test(); Test(10); Test(10, 20); Test(10, 20, 30); return 0; } cout cout cout cout cout cout cout return a + b; } double Test(double a, double b) { return a + b; } double Test(int a, double b) { return a + b; } int main() { cout // return 0; //} // //int fxx() //{ // return 0; //} int a = 0; // 引⽤:b和c是a的别名 int& b = a; int& c = a; // 也可以给别名b取别名,d相当于还是a的别名 int& d = b; ++d; // 这⾥取地址我们看到是⼀样的 cout const int a = 10; //变量a是只读的 //这里的b属于权限的放大,编译会报错 int& b = a; //b是a的别名,但b是可读可写的 const int& c = a; //c是a的别名,和a一样,c是只读的 return 0; } int a = 10; //可读可写 const int& b = a; //只读权限 //打印b(读权限) cout double d = 2.2; int& a = d; //编译不通过,会报错 const int& b = d; return 0; } int temp = *p1; *p1 = *p2; *p2 = temp; } void Swap2(int& rx, int& ry) { int temp = rx; rx = ry; ry = temp; } int main() { int x = 3, y = 5; Swap1(&x, &y); // C传参 Swap2(x, y); // C++传参 return 0; } static int n = 0; n++; return n; } int main() { int ret = Cout(); cout static int n = 0; n++; return n; } int main() { int ret = Cout(); cout return x + y; } int main() { int ret = 0; ret = Add(1, 2); return 0; } return x + y; } int main() { int ret = 0; ret = Add(1, 2); return 0; } cout f(10); return 0; } int* p1 = NULL; int* p2 = 0; } cout cout f(0); //调用f(int) f(NULL); //也是调用f(int) return 0; }