一、什么是C++
C++(c plus plus)是一种计算机高级程序设计语言,由C语言扩展升级而产生 ,最早于1979年由本贾尼·斯特劳斯特卢普在AT&T贝尔工作室研发。
我们之前学习的C语言就是一种面向过程的语言,它强调事件的具体实现过程,一般以函数来具体实现。C++就是一门典型的面向对象的语言,它将问题分成多个对象,更强调对象与对象之间的联系。它完善了C语言的许多缺陷,并且引入了面向对象的程序设计思想,包括面向对象的四个特性:封装,继承,多态,抽象。
无论是面向过程还是面向对象的语言,都有其优缺点:
面向过程 | 面向对象 | |
优点 | 流程化分工明确,效率高 | 结构化更清晰,易维护 |
缺点 | 可维护性差,扩展能力差 | 开销大,性能低 |
二、C++的标准库
标准的 C++ 由三个重要部分组成:
- 核心语言,提供了所有构件块,包括变量、数据类型和常量,等等。
- C++ 标准库,提供了大量的函数,用于操作文件、字符串等。
- 标准模板库(STL),提供了大量的方法,用于操作数据结构等。
这三个部分包含了C++这门语言的核心,我们后面的内容就主要围绕上面三个部分展开。
三、第一个C++程序
C++兼容C语言的大多数语法,所以C语言实现的 hello world 依旧可以运行,C++中需要把定义文件代码后缀改成.cpp,vs编译器看到是.cpp就会调用C++编译器,Linux下亚勇g++编译,不再是gcc。
当然C++有一套自己的输入输出,严格说C++版本的 hello world 应该是这么写:
// test.cpp // 这⾥的std cout等我们都看不懂,没关系,下⾯我们会依次讲解 #include<iostream> using namespace std; int main() { cout << "hello world\n" << endl; return 0; }
四、命名空间
4.1 域作用限定符
作用域限定符: " : ",其作用是通知编译器应从作用域限定符左侧的名字所示的作用域中寻找右侧那个名字,即指定访问哪个名字空间的哪个成员。当左侧为空时,默认访问的就是全局域。
#include<iostream> int a = 1; int main() { int a = 0; printf("%d\n", a); printf("%d\n", ::a); return 0; }
我们知道C语言遵循局部优先的规则,即当局部变量与全局变量冲突时,默认使用局部变量。而在C++中,我们可以通过域作用限定符来访问全局变量。
输出结果为:
0
1
4.2 为什么要存在命名空间
在C/C++中,变量、函数和后⾯要学到的类都是⼤量存在的,这些变量、函数和类的名称将都存在于全 局作⽤域中,可能会导致很多冲突。使⽤命名空间的⽬的是对标识符的名称进⾏本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。
c语⾔项⽬类似下⾯程序这样的命名冲突是普遍存在的问题,C++引⼊namespace就是为了更好的解决这样的问题。
#include<iostream> #include<stdlib.h> int rand = 1; int main() { printf("%d\n", rand); return 0; }
当我们定义rand变量时,就会与stdlib库中的rand函数出现命名冲突,这在C语言中只能通过修改变量名称来解决。但是在C++中,我们可以就可以使用命名空间来解决。
4.3 命名空间的定义
定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员。
C++标准库都放在⼀个叫std(standard)的命名空间中。
4.3.1 正常的命名空间定义
namespace本质是定义出⼀个域,这个域跟全局域各自独立,不同的域可以定义同名变量,所以下⾯的rand不在冲突了。
#include<iostream> #include<stdlib.h> namespace ake { int rand = 1; } int main() { printf("%d\n", ake::rand); //使用域作用限定符,指定作用域 return 0; }
输出结果为 :1
4.3.2 命名空间的嵌套定义
namespace只能定义在全局,当然他还可以嵌套定义。
#include<iostream> using namespace std; namespace ake1 { int a = 1; namespace ake2//嵌套 { int Add(int a, int b) { return a + b; } } } int main() { cout << ake1::a << endl; //访问通过限定符依次访问 cout << ake1::ake2::Add(1, 1) << endl; return 0; }
4.3.3 多文件中同名定义合并
在同一个工程中(可以是同一个工程下的不同文件),我们可以定义多个名称相同的命名空间,在编译时命名空间会自动合并,认为是⼀个namespace,不会冲突。
namespace ake { int a = 1; } namespace ake { int b = 1; } //编译时会自动合并
4.4 命名空间的使用
编译查找⼀个变量的声明/定义时,默认只会在局部或者全局查找,不会到命名空间⾥⾯去查找。所以 下⾯程序会编译报错。所以我们要使⽤命名空间中定义的变量/函数,有三种⽅式:
4.4.1 指定命名空间访问
这我们在前面已经实验演示过,现在我们来演示一下访问C++标准命名空间。(cout,endl等常用函数都被定义在C++标准命名空间std中)。
#include<iostream> int main() { std::cout << "hello bite" << std::endl; return 0; }
指定命名空间访问,项⽬中推荐这种⽅式。
4.4.2 using 部分展开
在我们书写代码时,可能会频繁调用某个函数,这是我们可以使用using部分展开,来简化代码。使用方式为using 命名空间名称:: 成员。
#include<iostream> #include<stdlib.h> namespace ake { int a = 1; int b = 2; } using ask::a; int main() { printf("%d\n", a); printf("%d\n", a); printf("%d\n", a); printf("%d\n", a); printf("%d\n", ake::b); return 0; }
项⽬中经常访问的不存在冲突的成员推荐这种⽅式
4.4.3 using namespace 全部展开
除了部分展开,自然也有全局展开。其格式为using namespace 命名空间名。
#include<iostream> #include<stdlib.h> namespace ake { int a = 1; int b = 2; } using namespace ask; int main() { printf("%d\n", a); printf("%d\n", b); return 0; }
展开命名空间中全部成员,项⽬不推荐,冲突⻛险很⼤,⽇常⼩练习程序为了⽅便推荐使⽤。
五、C++的输入和输出
C++的标准输入与输出函数是cin与cout,分别对应C语言的printf与scanf。但是相较于C语言,C++输入输出并不需要指定占位符,如:%d,%c等,输出可以⾃动识别变量类型。
#include<iostream> using namespace std;//展开命名空间 int main() { cout << "hello world" << endl; //endl相当于换行符 cout << "hello world" << '\n'; cout << 'a' << endl; int b = 1; cout << b << endl; cout << &b << endl; return 0; }
注:在C++中使用 cin 与 cout 以及 endl 都属于C++标准库,需要包含头文件iostream以及std标准命名空间。
六、缺省参数
6.1 缺省参数的使用
缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参缺省值,否则使用指定的实参。
void func(int a = 0) { cout << a << endl; } int main() { func(); // 没有传参时,使用参数的默认值,输出0 func(1); // 传参时,使用指定的实参,输出1 return 0; }
运行结果:
0
1
6.2 缺省参数的分类
根据其缺省参数的个数,我们我可以将缺省参数分为全缺省与半缺省。
6.2.1 全缺省
每一个参数都有缺省值。
#include<iostream> using namespace std; void func(int a = 0, int b = 1, int c = 2) { cout << "a = " << a << endl; cout << "b = " << b << endl; cout << "c = " << c << endl << endl;; } int main() { func();//不穿参数 func(10, 20);//半传参数 func(10, 20, 30);//全传 return 0; }
6.2.2 半缺省
只有一部分参数有缺省值,并且半缺省参数必须从右往左依次来给出,不能间隔着给。同时传参只能从左往右依次传参。
#include<iostream> using namespace std; void func(int a ,int b=1,int c=2) { cout <<"a = " << a << endl; cout << "b = " << b << endl; cout << "c = " << c << endl; } int main() { func(10,20);//半传参数 cout << endl; func(10, 20, 30);//全传 return 0; }
5.2.3 注意
在使用缺省参数时,我们也要知道一些注意事项:
1. 传参时不能间隔传参
void func(int a ,int b=1,int c=2) { cout <<"a = " << a << endl; cout << "b = " << b << endl; cout << "c = " << c << endl; } func(,10,20)//error
2. 缺省参数不能在函数的声明和定义同时出现
1. //test.h 2. void Func(int a = 10);//声明 3. // test.cpp 4. void Func(int a = 20)//定义 5. {}
深入计算机语言之C++:C到C++的过度-2