<<零基础C++第一期, C++入门基础>>
目录
编辑
什么是C++?
C++的发展史
命名空间
命名空间的定义
命名空间的使用
C++中的输入和输出
缺省参数
缺省参数的概念
缺省参数的分类
全缺省参数
半缺省参数
函数重载
nullptr
本次的大纲内容:
什么是C++?
C++(c plus plus)是一种计算机高级程序设计语言,由C语言扩展升级而产生。
C++既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行以继承和多态为特点的面向对象的程序设计。C++擅长面向对象程序设计的同时,还可以进行基于过程的程序设计。 C++几乎可以创建任何类型的程序:游戏、设备驱动程序、HPC、云、桌面、嵌入式和移动应用等。 甚至用于其他编程语言的库和编译器也使用C++编写。
C++拥有计算机运行的实用性特征,同时还致力于提高大规模程序的编程质量与程序设计语言的问题描述能力。
C++的发展史
C++的起源可以追溯到1979年,当时Bjarne Stroustrup(本贾尼·斯特劳斯特卢普,这个翻译的名字不 同的地⽅可能有差异)在⻉尔实验室从事计算机科学和软件⼯程的研究⼯作。⾯对项⽬中复杂的软件开 发任务,特别是模拟和操作系统的开发⼯作,他感受到了现有语⾔(如C语⾔)在表达能⼒、可维护性 和可扩展性⽅⾯的不⾜。
1983年,Bjarne Stroustrup在C语⾔的基础上添加了⾯向对象编程的特性,设计出了C++语⾔的雏形, 此时的C++已经有了类、封装、继承等核⼼概念,为后来的⾯向对象编程奠定了基础。这⼀年该语⾔被 正式命名为C++。
后来,因为在通过了标准化第⼀个草案之后,联合标准化委员会投票并通过了将STL包含到C++标准中的 提议。STL对C++的扩展超出C++的最初定义范围。虽然在标准中增加STL是个很重要的决定,但也因 此延缓了C++标准化的进程。
1997年11⽉14⽇,联合标准化委员会通过了该标准的最终草案。1998年,C++的ANSI/IS0标准被投⼊ 使⽤。
当然了,我们学习C++必须拜一下码头,认识一下本贾尼博士
语言的发展也是随着时代的进步,在逐步递进的,让我们来看看C++的历史版本:
命名空间
在C/C++中,变量、函数和后⾯要学到的类都是⼤量存在的,这些变量、函数和类的名称将都存在于全局作⽤域中,可能会导致很多冲突。
使⽤命名空间的⽬的是对标识符的名称进⾏本地化,以避免命名 冲突或名字污染,namespace关键字的出现就是针对这种问题的。
命名空间的定义
定义命名空间,需要使⽤到namespace关键字,后⾯跟命名空间的名字,然后接⼀对{}即可,{}中 即为命名空间的成员。命名空间中可以定义变量/函数/类型等。
1.命名空间的普通定义
//命名空间的普通定义
namespace bit //bit为命名空间的名称
{
int rand = 10;
int Add(int left, int right)
{
return left + right;
}
}
2.命名空间可以嵌套定义
//命名空间的嵌套定义
namespace bit //定义一个名为bit的命名空间
{
namespace pg //嵌套定义另一个名为pg的命名空间
{
int rand = 1;
int Add(int left, int right)
{
return left + right;
}
}
}
3.项⽬⼯程中多⽂件中定义的同名namespace会认为是⼀个namespace,不会冲突。
编译器最后会将其成员合成在同一个命名空间中。 所以我们不能在相同名称的命名空间中定义两个相同名称的成员。
命名空间的使用
编译查找⼀个变量的声明/定义时,默认只会在局部或者全局查找,不会到命名空间⾥⾯去查找。所以我们要使⽤命名空间中定义的变量/函数,有三种⽅式:
一、指定命名空间访问,项⽬中推荐这种⽅式。
符号“: :”在C++中叫做作用域限定符,我们通过“命名空间名称::命名空间成员”便可以访问到命名空间中相应的成员。
//加命名空间名称及作用域限定符
#include <stdio.h>
namespace bit
{
int a = 10;
int b = 20;
}
int main()
{
printf("%d\n", bit::a); 打印命名空间中的成员a
return 0;
}
二、using将命名空间中某个成员展开,项⽬中经常访问的不存在冲突的成员推荐这种⽅式。
我们还可以通过“using 命名空间名称::命名空间成员”的方式将命名空间中指定的成员引入。这样一来,在该语句之后的代码中就可以直接使用引入的成员变量了。
//使用using将命名空间中的成员引入
namespace bit
{
int a = 10;
int b = 20;
}
using bit::a; //将命名空间中的成员a引入
int main()
{
printf("%d\n", a); //打印命名空间中的成员a
return 0;
}
三、展开命名空间中全部成员,项⽬不推荐,冲突⻛险很⼤,⽇常⼩练习程序为了⽅便推荐使⽤。
最后一种方式就是通过”using namespace 命名空间名称“将命名空间中的全部成员引入。这样一来,在该语句之后的代码中就可以直接使用该命名空间内的全部成员了。
//使用using namespace 命名空间名称引入
namespace bit
{
int a = 10;
int b = 20;
}
using namespace bit; //将命名空间bit的所有成员引入
int main()
{
printf("%d\n", a);
return 0;
}
C++中的输入和输出
- <iostream>是 Input Output Stream 的缩写,是标准的输⼊、输出流库,定义了标准的输⼊、输出对象。
- std::cin 是 istream 类的对象,它主要⾯向窄字符(narrow characters (of type char))的标准输 ⼊流。
- std::cout 是 ostream 类的对象,它主要⾯向窄字符的标准输出流。
- std::endl 是⼀个函数,流插⼊输出时,相当于插⼊⼀个换⾏字符加刷新缓冲区
- <<是流插入运算符,>>是流提取运算符。(C语⾔还⽤这两个运算符做位运算左移/右移)
- 使⽤C++输⼊输出更⽅便,不需要像printf/scanf输⼊输出时那样,需要⼿动指定格式,C++的输⼊ 输出可以⾃动识别变量类型(本质是通过函数重载实现的,这个以后会讲到),其实最重要的是 C++的流能更好的⽀持⾃定义类型对象的输⼊输出。
- IO流涉及类和对象,运算符重载、继承等很多⾯向对象的知识,这些知识我们还没有讲解,所以这 ⾥我们只能简单认识⼀下C++ IO流的⽤法,后⾯我们会有专⻔的⼀个章节来细节IO流库。
- cout/cin/endl等都属于C++标准库,C++标准库都放在⼀个叫std(standard)的命名空间中,所以要 通过命名空间的使⽤⽅式去⽤他们。
- ⼀般⽇常练习中我们可以using namespace std,实际项⽬开发中不建议using namespace std。
- 这⾥我们没有包含,也可以使⽤printf和scanf,在包含间接包含了。vs系列 编译器是这样的,其他编译器可能会报错。
在我们学习C语言时,第一个写的代码就是在屏幕上输出一个"hello world",按照学习计算机语言的习俗,现在我们也应该使用C++来和这个世界打个招呼了:
#include <iostream>
using namespace std;
int main()
{
cout << "hello world!" << endl;
return 0;
}
缺省参数
缺省参数的概念
缺省参数是声明或定义函数时为函数的参数指定⼀个缺省值。在调⽤该函数时,如果没有指定实参 则采⽤该形参的缺省值(有些地⽅把 缺省参数也叫默认参数)
#include <iostream>
using namespace std;
void func(int a = 0)
{
cout << a << endl;
}
int main()
{
func(); //没有传参的时候,使用参数的默认值
func(10); //传参时,使用指定参数
return 0;
}
缺省参数的分类
全缺省参数
全缺省就是全部形参给缺省值
void Print(int a = 10, int b = 20, int c = 30)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
半缺省参数
半缺省就是部分形参给缺省值。C++规定半缺省参数必须从右往左 依次连续缺省,不能间隔跳跃给缺省值。
void Print(int a, int b = 20, int c = 30)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
注意:
缺省参数不能在函数声明和定义中同时出现
//错误示例
//test.h
void Print(int a, int b, int c = 30);
//test.c
void Print(int a, int b, int c = 30)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
缺省参数只能在函数声明时出现,或者函数定义时出现(二者之一均正确)
函数重载
C++⽀持在同⼀作⽤域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者 类型不同。这样C++函数调⽤就表现出了多态⾏为,使⽤更灵活。C语⾔是不⽀持同⼀作⽤域中出现同 名函数的。
#include<iostream>
using namespace std;
// 函数重载
int Add(int left, int right)
{
cout << "int Add(int left, int right)" << endl;
return left + right;
}
double Add(double left, double right)
{
cout << "double Add(double left, double right)" << endl;
return left + right;
}
int main()
{
Add(10, 20);
Add(10.1, 20.2);
return 0;
}
大家来看下面俩个函数是否构成函数重载:
void f1()
{
cout << "f()" << endl;
}
void f1(int a = 10)
{
cout << "f(int a)" << endl;
}
一定要记住,函数重载的定义是参数个数不同 和 函数的类型不同。 在这里是函数的参数个数不同,属于函数重载,但是f1()在调用时,会报错,因为编译器不知道调用哪个。
nullptr
NULL实际是⼀个宏,在传统的C头⽂件(stddef.h)中,可以看到如下代码:
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
C++中NULL可能被定义为字⾯常量0,或者C中被定义为⽆类型指针(void*)的常量。不论采取何种 定义,在使⽤空值的指针时,都不可避免的会遇到⼀些⿇烦,本想通过f(NULL)调⽤指针版本的 f(int*)函数,但是由于NULL被定义成0,调⽤了f(int x),因此与程序的初衷相悖。f((void*)NULL); 调⽤会报错。
C++11中引⼊nullptr,nullptr是⼀个特殊的关键字,nullptr是⼀种特殊类型的字⾯量,它可以转换 成任意其他类型的指针类型。使⽤nullptr定义空指针可以避免类型转换的问题,因为nullptr只能被 隐式地转换为指针类型,⽽不能被转换为整数类型。
#include <iostream>
using namespace std;
void f(int x)
{
cout << "f(int x)" << endl;
}
void f(int* ptr)
{
cout << "f(int* ptr)" << endl;
}
int main()
{
//f(NULL); // c++
//f((void*)0); // c
f(nullptr);
return 0;
}