初识c++

在结束了C语言的学习后,我开始了第一门面向对象语言的学习——C++。1982年,美国AT&T公司贝尔实验室的本贾尼博士在C语言的基础上引入并扩充了面向对象的概念,发明了—种新的程序语言。 为了表达该语言与C语言的渊源关系,它被命名为C++。 而本贾尼博士被尊称为C++语言之父。C++基本可以兼容C语言,也对C语言中的一些问题进行了修改,最重要的就是扩充了面向对象的概念,接下来让我们一起来学习C++吧。

一 C++目前的主流版本和发展

目前C++的主流版本有C++11、C++14、C++17、C++20。C++正式发布于1998年,C++98也就是C++官方的第一个版本,在2003年C++迎来了一次更新,修改了C++98标准的一些错误和漏洞,同时引入了一些新的功能,如trl库,而下一次更新时间在2011年,这是一次革命性的更新,增加了大量的新特性和功能,引入了智能指针、lambda表达式、线程支持等,后来就保持着3年一次的更新频率,最近一次较大的更新是C++20,引入了概念(Concepts)、模块化(Modules)等。

二 C++的重要性

TIOBE排行榜 [1]是根据互联网上有经验的程序员、课程和第三方厂商的数量,并使用搜索引擎(如Google、Bing、Yahoo!)以及Wikipedia、AmazonYouTube和Baidu(百度)统计出排名数据,可以反映某个语言在一段时间的热度。下表为今年7月的最新榜单,在6月时,可以看到C++排到了第二的位置。

C++的应⽤领域服务器端、游戏(引擎)、机器学习引擎、⾳视频处理、嵌⼊式软件、电信设备、⾦融 应⽤、基础库、操作系统、编译器、基础架构、基础⼯具、硬件交互等很多⽅⾯都有。

三c++的第一个程序

经过前面的了解,相信你对C++已经有了一个简单的认识,那现在让我们来编写C++的第一个程序吧。

//用C++打印hello world
#include <iostream>
using namespace std;
int main()
{
   cout<<"hello world"<<endl;
   return 0;
}

1.程序介绍

1.1命名空间

学过C语言的你可能会觉得有一种既熟悉又陌生的感觉,下面我来带你了解一下这段代码。

第一行自然是包含头文件了,iostream是input output stream的缩写,这个头文件定义了基本的输入输出流,流是C++引入的一个新的概念,它不同于C语言,在输入和输出时不需要程序员来指定输入和输出的数据类型,编译器会自动识别,极大方便了输入和输出。

namespace 是一个命名空间,它的后面跟命名空间的名字,它可以解决程序中名字冲突的问题,咱们上代码来体验一下。

通过编译器的报错我们可以看出如果我们自己定义的变量与库函数冲突,程序就无法正常运行,这种情况我们就可以使用命名空间来解决这个问题。

使用命名空间后,命名冲突的问题就解决了,不过在使用时我们需要在变量前加范围解析运算符::,它可以明确指定标识符属于哪个命名空间,using是一个关键字,它可以用来引入命名空间,这样使用后就不用在标识符前加范围解析运算符了,不过全部展开在开发大型项目时也是有风险的,如果有使用较多的标识符可以采用以下方法。

//全部展开会有风险推荐使用using 命名空间::标识符
using namespace std;

可以选择只展开某个常用的标识符。在我们日常使用时就不用考虑那么多了,全部展开也不会有太大的风险,所以这种方法仅供参考。

C++的标准库都放在一个叫std(standard)的命名空间中,展开后cin、cout等一些输入输出函数就不用加范围解析运算符了。

命名空间还可以嵌套使用,想要正确访问数据就必须理解命名空间间的嵌套关系。

1.2流提取和流插入

>>和<<是C++引入的流提取和流插入运算符,在C语言中这两个运算符做位运算左移和右移,它可以自动识别数据类型,不需要像C语言指定数据类型,但是如果不能正确输入数据,最后输出的结果会很奇怪。

#include <iostream>
using namespace std;
int main()
{
    int a=10;
    double b=2.22222;//精度为5位小数
    char c='d';
    cin>>a>>b>>c;
    cout<<a<<" "<<b<<" "<<c<<" "<<endl;
    return 0;
}
    

在这个程序里,本该为int的数据输入了double,编译器把10.2看成了两个数,最后字符类型的数据就没有正常输出。

三.缺省参数

缺省参数是声明或定义函数时,在调用函数时,如果没有指定指定实参,就使用形参的缺省值,缺省参数分为全缺省和半缺省,在指定缺省参数时,只能从右往左指定缺省参数,也不可以跳跃指定缺省参数,缺省参数不能在函数声明和函数定义同时出现。

//下面这几种指定缺少参数的方法是错误的
void add(int x=10,int y=20,int z);//应该从右往左
void add(int x=10,int y,int z=10);//不能跳跃指定缺省参数
//函数调用时以下方法也是错的
void(,20,);//暂时不知道传什么参数可以先使用原来指定的缺省参数

//这种也是正确的
void add(int x=10,int y=20);
add(20);//没有传参的使用缺省参数

四.函数重载

在C语言中不允许同名函数的存在,而在c++中,同名函数可以存在,只要函数的形参个数和数据类型不同就可以,这种方法被称为函数重载,需要注意的是不能以返回值类型区分重载函数。

#include <iostream>
using namespace std;
//这种是正确的
int add(int x, int y)
{
	return x + y;
}
double add(double x, double y)
{
	return x + y;
}
//这种重载也是正确的,只是举个例子
double add(double x,int y,double z)
{
    return x+y+z;
}
//这种是错误的,不能以返回值类型来重载函数
//void add(int x)
//{

//}
int main()
{
	add(10, 20);
	add(1.1, 2.2);
	return 0;
}

五.引用

1.引用的使用

引用也是c++新引入的概念,它与使用的是&,和取地址符一样,不过它可不是为了取地址,但是它不会开辟内存,他只是给变量取一个新的名字,它的本质是一个指针常量,所以在使用时必须初始化。

int a=10;

//int &b;//也是错误的,没有初始化
int &b =a;
int &c=a;

c++;

从调试中可以看出b,c和a共享同一份数据。从上面的代码可以看出引用使用时必须初始化,可以对一个变量多次引用,即取多个别名。

如果引用已经引用了一个实体,那么它不能在引用别的实体,可以看下面的例子,如果c变成了d的别名,那么按照引用的规则,c与d的地址应该是相同的,但是从输出结果来看并不相同,所以c=d只是一个简单的赋值操作,并不是引用。

下面我们来了解一下引用的使用,在函数传参时,有了引用这个概念我们就不用传地址了,取别名可以很好的解决这个问题,只需要传参数就可以。

//函数传址调用
void swap(int *x, int *y)
{
	int  temp = *x;
	*x = *y;
	*y = temp;
}
//函数传值调用
void swap(int& x,int& y)
{
    int  temp=x;
    x=y;
    y=temp;
}
int main()
{
    int x=20;
    int y=30;
    //传址调用
    swap(&x,&y);
    //传值调用
    swap(x,y);
}
2.const引用

在某些情况下,引用的对象是一个表达式或者需要进行隐式类型转换时,这是会产生一个临时对象,所谓临时对象就是编译器需要⼀个空间暂存表达式的求值结果时临时创建的⼀个未命名的对象,c++规定临时对象具有常性,不加const引用就会告诉你“非常量引用的初始值必须位左值”,解决办法为在引用前加const限定,下面是几个需要加const限定的例子。

int a=10;
int b=10;
//int &c= a+b;这是错误的,编译器会报错
const int &c=a+b;//这是正确的


const int a=10;
//int &b=a;这是错误的,原本a只有读的权限,由于b是a的别名,b没有加const限定,那么b本来就有读和写 
 //的权限,这就造成了权限的放大。
//同理,有权限的放大,就有权限的缩小
int a=10;
const int &b=a;//这句话没有报错,说明权限只可以缩小,不可以放大。

//存在隐式类型转换的引用
int a=10;
//int &b=a*1.0;表达式的结果需要创建一个临时对象来返回,而临时对象具有常性,需要加const限定
const int &b=a*1.0;

double a=10.2;
//int &b=a;同样需要进行隐式类型转换,需要加const限定
const int &b=a;

const引用还可以方便函数传参,如果需要给一个函数传常量时,普通引用就会有权限放大,const不会出现这种情况。

六.内联函数

被inline修饰的函数叫做内联函数,在调用内联函数的时候编译器会将其自动展开,就不用创建栈帧了,可以提高效率。它和C语言中的宏函数不同,宏函数是在预处理时展开,不方便调试,且不安全,预处理器只是简单地进行文本替换,它不会检查类型安全或语法正确性。这意味着任何宏展开中的错误只有在实际代码编译时才会被发现。所以c++设计了内联函数来替代宏函数。

inline int ADD(int x,int y)
{
    return x+y;
}
int main()
{
    int ret=ADD(1,2);
    int ret=ADD(1,2);
    int ret=ADD(1,2);
    int ret=ADD(1,2);
}

内联函数只是我们对编译器的一个建议,是否调用主要取决于编译器,其原因是如果展开的是递归语句且调用多次,可能会有栈溢出的风险,在调用时我们可以通过汇编指令是否出现call来判断编译器是否展开了内联函数,如果出现就证明没有展开。内联函数不要定义和实现分离,因为内联函数在C++中默认是没有地址的,连接时会报错。

七.nullptr

在C语言中,空指针被定义为NULL,而在c++中,NULL在某些地方的使用会出现问题,所以c++引入了一个新的关键字nullptr,它就是指空指针。

从程序的调用结果来看,NULL在C++中并不是空指针的意思,反而像是一个整型,让我们来看一下NULL在C++中的定义。

我们可以看到NULL在c++中被定义为0而不是空指针。那如果想利用空指针来调用第二个函数,应该怎么实现呢,如果采用上图中(void*)0的传参方式,编译器会告诉你没有与参数列表匹配的重载函数,这是因为在C语言中void*可以转换成任意类型的指针,在c++中则不可以,这也就说明了为什么函数的调用结果会是调用两次第一个函数。所以为了解决这个问题,c++引入了nullptr这个关键字,可以很好的解决这个问题,在上面这个程序中使用f(nullptr)传参会得到正确结果。

好了,C++初始就讲到这里了,如果觉得写的还不错的可以点赞收藏,如果有写的不对的地方还请批评指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值