概述
C++可以追溯到1979年,C++之父Bjarne Stroustrup在在使用C语言研发工作时发现C语言的不足,并想要将其改进,到1983年,Bjarne Stroustrup在C语言的基础上添加了面向对象编程的特性,设计出了C++的雏形。
网址推荐
C++官方文档(英文):cppreference.com
C++官方文档(中文):C++ 参考手册 - cppreference.com
C++函数查询:Reference - C++ Reference
C++程序
C++兼容C的绝大多数语法,所以我们仍可以在C++文件中使用printf函数
#include <stdio.h>
int main()
{
printf("hello world");
return 0;
}
类似于C的#include <stdio.h>,C++中也有一个标准库. 我们想要调用就要用:#include <iostream>,所以,严格来说用C++写出的printf函数应该是这样写的:
#include<iostream>
using namespace std;
//命名冲突->命名空间
int main()
{
cout << "hello world" << endl;
return 0;
}
接下来,我们一一讲解代码中的元素.
当需要多人完成一个项目时,若两人用了相同的变量名,但变量的值却不同该怎么办?
namespace命名空间
1.定义命名空间,需要使⽤到namespace关键字,后⾯跟命名空间的名字,然后接⼀对{}即可{}中即为命名空间的成员。命名空间中可以定义变量/函数/类型等。
2.namespace本质是定义出⼀个域,这个域跟全局域各⾃独⽴,不同的域可以定义同名变量,所以下⾯的rand不在冲突了。
3.C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找⼀个变量/函数/类型出处(声明或定义)的逻辑,所有有了域隔离,名字冲突就解决了。局部域和全局域除了会影响编译查找逻辑,还会影响变量的声明周期,命名空间域和类域不影响变量声明周期。
4.namespace只能定义在全局,当然他还可以嵌套定义。
5.项⽬⼯程中多⽂件中定义的同名namespace会认为是⼀个namespace,不会冲突。
6.C++标准库都放在⼀个叫std(standard)的命名空间中。
namespace的使用
如果写出这样的代码:
int main()
{
int rand = 10;
//编译报错:error C2365: “rand”: 重定义;以前的定义是“函数”
printf("%p\n", rand);//查找是编译进行的
return 0;
}
会出现重定义报错
所以我们使用命名空间:
//“ ::”域作用限定符,不写即为先从全局开始查找,也可以写具体的域
namespace Frenemy
{
int rand = 10;
}
int main()
{
//编译报错:error C2365: “rand”: 重定义;以前的定义是“函数”
printf("%d\n", Frenemy::rand);//查找是编译进行的
return 0;
}
其中“ ::”域作用限定符,不写即为先从全局开始查找,也可以写具体的域,并且命名空间必须写在全局变量中.
而对于多个文件中的相同的命名空间,C++会直接将其合并.
若在一个项目中,已经使用了一次命名空间,但仍有两人使用相同变量又该怎么办呢?
namespace的嵌套调用
在同一个命名空间中,假如有两人ab与xy,我们就可以使用嵌套定义:
namespace Frenemy
{
namespace ab
{
int rand = 1;
}
namespace xy
{
int rand = 2;
}
我们如果要使用命名空间的值,例如ab里的rand,则使用Frenemy::ab::rand即可
namespace的展开
全部展开:使用using Frenemy(namespace)
部分展开(只展开一个变量):使用using Frenemy(namespace)::ab::rand.要使用时直接调用rand变量即可.
对于标准库函数standard(简称std), 每次写语句时都要使用std::cout<<a<<std::endl;较为麻烦,所以对于平时小练习可以将标准库函数直接展开.
C++输入输出
<iostream> 是 Input Output Stream 的缩写,是标准的输⼊、输出流库,定义了标准的输⼊、输出对象。
std::cin 是 istream 类的对象,它主要⾯向窄字符(narrow characters (of type char))的标准输⼊流。
std::cout 是 ostream 类的对象,它主要⾯向窄字符的标准输出流。
std::endl 是⼀个函数,流插⼊输出时,相当于插⼊⼀个换⾏字符加刷新缓冲区。
<<是流插⼊运算符,>>是流提取运算符。(C语⾔还⽤这两个运算符做位运算左移/右移)
C++一行可以输入输出多个字符和字符串,并且可以自动识别多种类型
c语言中的printf在C++中就相当于输出函数cout.
int main()
{
printf("hello world!\n");
cout << "hello world!" << endl;
return 0;
}//这两者是同一效果
缺省参数
缺省参数是声明或定义函数时为函数的参数指定⼀个缺省值。在调⽤该函数时,如果没有指定实参则采⽤该形参的缺省值,否则使⽤指定的实参,缺省参数分为全缺省和半缺省参数。(有些地⽅把缺省参数也叫默认参数)
带缺省参数的函数调⽤,C++规定必须从左到右依次给实参,不能跳跃给实参。
函数声明和定义分离时,缺省参数不能在函数声明和定义中同时出现,规定必须函数声明给缺省值。
全缺省参数
全部形参给缺省值,例如:
// 全缺省
void Func1(int a = 10, int b = 20, int c = 30)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl << endl;
}
要调用函数时就可以不用给形参,如果要给形参,则只能按顺序从前往后给且不能跳着给.
半参省参数
// 半缺省
void Func2(int a, int b = 10, int c = 20)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl << endl;
}
半参省参数的规定是从右向左给形参赋值,也不能跳着给.
函数重载
C++⽀持在同⼀作⽤域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者类型不同。这样C++函数调⽤就表现出了多态⾏为,使⽤更灵活。C语⾔是不⽀持同⼀作⽤域中出现同名函数的。
参数类型不同
相同函数名的函数其形参类型不同则为函数重载,例如:
// 1、参数类型不同
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;
}
参数个数不同
相同函数名的函数其形参个数不同则为函数重载,例如:
// 2、参数个数不同
void f(int a, int b)
{
cout << "f(int a, int b)" << endl;
}
void f(int a)
{
cout << "f(int a)" << endl;
}
参数类型顺序不同
相同函数名的函数其形参顺序不同则为函数重载,例如
void f(int a, char b)
{
cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
cout << "f(char b, int a)" << endl;
}
注意
1.需要注意的是,返回值不同并不能说明两函数为函数重载,因为函数返回值可以不被调用;如果其中一个没有返回值,而另一个有,当需要返回值时也无法区分 .
2.下列函数f()调用时会报错,因为编译器不知道执行哪一个!
// 下⾯两个函数构成重载
// f()但是调⽤时,会报错,存在歧义,编译器不知道调⽤谁
void f1()
{
cout << "f()" << endl;
}
void f1(int a = 10)
{
cout << "f(int a)" << endl;
}
引用
引⽤不是新定义⼀个变量,⽽是给已存在变量取了⼀个别名,编译器不会为引⽤变量开辟内存空间,它和它引⽤的变量共⽤同⼀块内存空间。我们可以粗浅的将其理解为没有开辟新空间的指针.
引用的特性
1.引⽤在定义时必须初始化
2.⼀个变量可以有多个引用
3.引⽤⼀旦引⽤⼀个实体,再不能引⽤其他实体
例如
int main()
{
int a = 0;
// 引⽤:b和c是a的别名,放在类型后面就是引用,别名相当于指针,但别名的地址与原变量相同
int& b = a;
int& c = a;
// 也可以给别名b取别名,d相当于还是a的别名
int& d = b;
//这⾥取地址我们看到是⼀样的
++d;
cout << &a << endl;
cout << &b << endl;
cout << &c << endl;
cout << &d << endl;
return 0;
}
相当于为变量取外号 .
例如我们熟悉的Swap函数,用指针写是这样:
void Swap(int* rx, int* ry)
{
int tmp = *rx;
*rx = *ry;
*ry = tmp;
}
用引用写是这样:
void Swap(int& rx, int& ry)
{
int tmp = rx;
rx = ry;
ry = tmp;
}
看起来确实简洁一点, 这些就是引用的一些基础知识。
总结
学会这几个知识点,我们就可以理解开篇的那个函数代表了什么意思了。
C++中许多新语法的提出,其实也就是Bjarne Stroustrup对C语言一些语法的不满并对其进行的改造。我们可以发现,这几个知识点确实对应着C语言语法里一些较为不方便的地方。