这篇着重介绍C语言中的不足的解决方法和为学习C++做铺垫。
目录
C++输入&输出
输出
下面是C++打印"hello world"。
cpp
#include <iostream>
using namespace std;
int main()
{
cout << "hello world" << endl;
return 0;
}
这里的打印换成了cout,<<和endl这要怎么理解呢?
- cout:cout是标准输出对象(控制台),必需包含<iostream>头文件(类似于C语言的stdio.h)以及按命名空间使用方法使用std(在命名空间会有介绍)。
- endl:是特殊的C++符号表示换行输出,相当于是'\n'。也包含在<iostream>头文件中。
- <<:流插入运算符。
输入
上面的是输出那输入要怎么实现呢?利用cin和>>即可实现。
- cin:cin是标准输入对象(键盘),其他和cout一样。
- >>:流提取运算符。
cpp
#include <iostream>
using namespace std;
int main()
{
int a = 0;
cout << "请输入:";
cin >> a;
cout << "输出:";
cout << a << endl;
return 0;
}
使用C++的输入输出并不需要像C语言一样自己手动控制格式,C++可以自动识别变量的类型 。
命名空间
定义
现在有一个项目分配给两个人让他们实现。他们写的都没问题但是它们一合并就出现了命名冲突的问题。在C++里就可以避免此问题的发生。C++提出了命名空间这是对标识符的名称进行本地化,以避免命名冲突。
定义命名空间需要用到namespace关键字,后面接命名空间的名字,然后接一对{}即可。
cpp
namespace zz
{
int a = 1;
int b = 2;
}
命名空间里面不止可以定义变量 也可以定义函数 和类型 ,注意一个命名空间就定义了一个新的作用域,命名空间里的所有内容只限于该命名空间中。
应用
命名空间里的成员要怎么用呢?要用到范围解析运算符(::),具体如下:
如果命名空间里存在函数和结构体该怎么用呢?
假设该函数为fun(形参),zz::fun(形参)即可。
假设该结构体为struct Node,struct zz::Node即可。
如果命名空间里的所有变量使用的都很频繁那可以用using引入。
cpp
#include <iostream>
using namespace std;
namespace zz
{
int a = 1;
int b = 2;
}
using namespace zz;
int main()
{
cout << a << endl;
return 0;
}
大家可能注意到了在头文件的下面都有这么一段话using namespace std;,cout和cin在命名空间std里,这其实是把cout和cin引入。
如果命名空间里的某个变量使用的很频繁那也可以用using引入。
cpp
#include <iostream>
using namespace std;
namespace zz
{
int a = 1;
int b = 2;
}
using zz::a;
int main()
{
cout << a << endl;
return 0;
}
缺省参数
定义
缺省参数是声明或定义函数时为函数的参数指定一个缺省值,在调用该函数时如果没有实参的传入那就用缺省值,如果有那就用实参。
缺省参数分为两种:
全缺省参数
cpp
void Func(int a = 1, int b = 2)
{
cout << a << endl;
cout << b << endl;
}
半缺省参数
cpp
void Func(int a, int b = 2)
{
cout << a << endl;
cout << b << endl;
}
注意:半缺省参数必须从右往左 依次来给出,不能隔着给。缺省参数不能在函数声明和定义中同时出现。缺省参数的值必须是常量 和全局变量。
函数重载
在C语言中写功能相同的函数常常因为传入的数据类型不同而需要写不止一个函数,在C++中用一个函数即可解决。
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数或类型或类型顺序)不同,常用来处理实现功能类似数据类型
不同的问题。
函数重载虽然方便但是要注意使用。例如:无参的函数和全缺省参数(在没有传入参数的情况下)。
像上面这种就会报对重载函数的调用不明确的错误,平时在写的时候一定要注意!
引用
定义
大家在学习指针时一定遇到了各种困难,当时我在想有没有什么可以平替指针,C++里的引用可以实现(平替也不是绝对的,只是在一定程度可以替换指针,事实上引用和指针是相辅相成的。引用的底层逻辑其实就是指针)。
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
引用需要用引用运算符(&),具体运用如下:
cpp
int a = 0;
int& ra = a;
特性
引用的特性
- 引用在定义时必须初始化。
- 一个变量可以有多个引用。
- 引用一旦引用了一个实体,就不能在引用其他实体。
应用
引用一般用于做函数的参数 和**返回值,**这样可以减少拷贝从而增加效率。
最典型的做函数的参数莫过于两数相互交换。 没学之前是这样写的:
cpp
void Swap(int* p1, int* p2)
{
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
现在就可以这样写:
cpp
void Swap(int& p1, int& p2)
{
int temp = p1;
p1 = p2;
p2 = temp;
}
const
当const修饰一个变量时,该变量就变成只能读不能改。如果更改就会报错如下:
如果这时候引用a会怎样?
可以看到依然报错 ,因为你引用了就代表了a的值可以被ra更改(因为只限定了a没限定ra)这样权限就放大了,但是权限只能平移个缩小所以会报错。只要像前面在加一个const即可。
其实加const不仅仅可以这样玩也可以像下面这样玩。
cpp
#include <iostream>
using namespace std;
int main()
{
int a = 0;
int b = 0;
const int& ri = (a + b);
return 0;
}
是不是很神奇为什么呢?a+b算完后会把该值放在临时对象 中该对象具有常性,就像上面说的用const修饰的a一样。
引用与指针的区别
- 引用不会创建一片空间,他只是一个变量的别名。指针会开辟一片空间。
- 引用在初始化时必须初始化,指针可以不初始化但建议初始化。
- 引用在引用了一个实体化后就不能在引用其他的实体了。指针可以指向同类型的不同实体。
- 引用所占的字节数是其引用类型的大小,指针所占的字节数4/8字节。
- 引用在访问实体是可以直接用,指针需要解引用。
inline
以inline修饰的函数叫做内联函数 ,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率。这个类似与C语言里的宏函数,但它没有宏函数的那么多规定。
cpp
inline void Print(int a)
{
cout << a << endl;
}
int main()
{
Print(1);
return 0;
}
inline是以空间换时间的做法,在编译阶段,会用函数体代替函数调用。不过inline对于编译器只是建议如果函数规模小那就会展开,如果函数很大就不会展开而是会调用。inline的声明和定义不能分开,分离会导致链接错误。因为inline被展开,就没有函数的地址了,链接就会找不到。
nullptr
nullptr是C++11中引入的一个关键字用于表示空指针类型。之前C++用的还是NULL但是由于某些问题所以换成了nullptr。以后在C++里用空指针用nullptr即可。