前言
也是好久没写博客了,那些天也没闲着,去练题去了。实际上练题也可以写练题的博客,但是觉得太简单了些,于是就没有继续写下去。如今又回来写博客,是因为有整理了新的知识C++。内容不算多,大多数都是书本上内容的转述。小伙伴们可以酌情观看,捧捧场。
大概就简单的写写C++的来源和概况,以及C++中和C语言中的一些不同,对于C语言来说的优势,等等。
一、C++的来源
1、C++的简介
C++(c plus plus)是一种计算机高级程序设计语言,由C语言扩展升级而产生 ,最早于1979年由本贾尼·斯特劳斯特卢普在AT&T贝尔工作室研发。
C++既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行以继承和多态为特点的面向对象的程序设计。C++擅长面向对象程序设计的同时,还可以进行基于过程的程序设计。 C++几乎可以创建任何类型的程序:游戏、设备驱动程序、HPC、云、桌面、嵌入式和移动应用等。 甚至用于其他编程语言的库和编译器也使用C++编写。
C++拥有计算机运行的实用性特征,同时还致力于提高大规模程序的编程质量与程序设计语言的问题描述能力。
2、发展历史
1970年,AT&T贝尔实验室的工作人员D.Ritchie和K.Thompson共同研发了C语言。研制C语言的初衷是用它编写UNIX系统程序,因此,实际上C语言是UNIX的“副产品”。
1971年,瑞士联邦技术学院N.Wirth教授发明了第一个结构化的编程语言Pascal。
20世纪70年代中期,本贾尼·斯特劳斯特卢普在剑桥大学计算机中心工作。斯特劳斯特卢普希望开发一个既要编程简单、正确可靠,又要运行高效、可移植的计算机程序设计语言。而以C语言为背景,以Simula思想为基础的语言,正好符合斯特劳斯特卢普的初衷和设想。
1979年,本贾尼·斯特劳斯特卢普到了AT&T贝尔实验室,开始从事将C改良为带类的C(C with classes)的工作。、1983年,该语言被正式命名为C++。
1985年、1990年和1994年,C++先后进行3次主要修订。
C++的标准化工作于1989年开始 [21],并成立了一个ANSI和ISO(International Standards Organization)国际标准化组织的联合标准化委员会。
1994年1月25曰,联合标准化委员会提出了第一个标准化草案。在该草案中,委员会在保持斯特劳斯特卢普最初定义的所有特征的同时,还增加了部分新特征。
在完成C++标准化的第一个草案后不久,亚历山大·斯特潘诺夫(Alexander Stepanov)创建了标准模板库(Standard Template Library,STL)。在通过了标准化第一个草案之后,联合标准化委员会投票并通过了将STL包含到C++标准中的提议。STL对C++的扩展超出了C++的最初定义范围。虽然在标准中增加STL是个很重要的决定,但也因此延缓了C++标准化的进程。
1997年11月14日,联合标准化委员会通过了该标准的最终草案。
1998年,C++的ANSI/IS0标准被投入使用。
3、C++语言标准
自C++的ANSI/IS0标准投用以来,共进行过5次更新。
标准版本 |
发布时间 |
正式名称 |
更新内容 |
---|---|---|---|
C++ 03 |
2003年 |
ISO/IEC 14882:2003 |
对C++ 98版本的漏洞做了部分修改。 |
C++ 11 |
2011年8月12日 |
ISO/IEC 14882:2011 |
对容器类的方法做了三项主要修改: 1、新增了右值引用,可以给容器提供移动语义。 2、新增了模板类initilizer_list,因此可将initilizer_list作为参数的构造函数和赋值运算符。 3、新增了可变参数模板(variadic template)和函数参数包(parameter pack),可以提供就地创建(emplacement)方法。 |
C++ 14 |
2014年8月18日 |
ISO/IEC 14882:2014 |
C++11的增量更新。主要是支持普通函数的返回类型推演,泛型lambda,扩展的lambda捕获,对constexpr函数限制的修订,constexpr变量模板化等。 |
C++ 17 |
2017年12月6日 |
ISO/IEC 14882:2017 |
新增UTF-8 字符文字、折叠表达式(fold expressions):用于可变的模板、内联变量(inline variables):允许在头文件中定义变量;在if和switch语句内可以初始化变量;结构化绑定(Structured Binding):for(auto [key,value] : my_map){…};类模板参数规约(Class Template Argument Deduction):用pair p{1, 2.0}; 替代pair{1, 2.0};;>;static_assert的文本信息可选;删除trigraphs;在模板参数中允许使用typename(作为替代类);来自 braced-init-list 的新规则用于自动推导;嵌套命名空间的定义;允许命名空间和枚举器的属性;新的标准属性:[[fallthrough]], [[maybe_unused]] 和 [[nodiscard]];对所有非类型模板参数进行常量评估;Fold表达式,用于可变的模板;A compile-time static if with the form if constexpr(expression);结构化的绑定声明,允许auto [a, b]=getTwoReturnValues()。 |
C++ 20 |
2020年12月7日 |
ISO/IEC 14882:2020 |
新增模块(Modules)、协程(Coroutines)、范围 (Ranges)、概念与约束 (Constraints and concepts)、指定初始化 (designated initializers)、操作符“<=> != ==”;constexpr支持:new/delete、dynamic_cast、try/catch、虚拟、constexpr向量和字符串;计时:日历、时区支持。 |
4、C++语言特点
4.1、与C语言的兼容性
C++与C语言完全兼容,C语言的绝大部分内容可以直接用于C++的程序设计,用C语言编写的程序可以不加修改地用于C++。
4.2、数据封装和数据隐藏
在C++中,类是支持数据封装的工具,对象则是数据封装的实现。C++通过建立用户定义类支持数据封装和数据隐藏。
在面向对象的程序设计中,将数据和对该数据进行合法操作的函数封装在一起作为一个类的定义。对象被说明为具有一个给定类的变量。每个给定类的对象包含这个类所规定的若干私有成员、公有成员及保护成员。完好定义的类一旦建立,就可看成完全封装的实体,可以作为一个整体单元使用。类的实际内部工作隐藏起来,使用完好定义的类的用户不需要知道类的工作原理,只要知道如何使用它即可。
4.3、支持继承和重用
在C++现有类的基础上可以声明新类型,这就是继承和重用的思想。通过继承和重用可以更有效地组织程序结构,明确类间关系,并且充分利用已有的类来完成更复杂、深入的开发。新定义的类为子类,成为派生类。它可以从父类那里继承所有非私有的属性和方法,作为自己的成员。
4.3、多态性
采用多态性为每个类指定表现行为。多态性形成由父类和它们的子类组成的一个树型结构。在这个树中的每个子类可以接收一个或多个具有相同名字的消息。当一个消息被这个树中一个类的一个对象接收时,这个对象动态地决定给予子类对象的消息的某种用法。多态性的这一特性允许使用高级抽象。
继承性和多态性的组合,可以轻易地生成一系列虽然类似但独一无二的对象。由于继承性,这些对象共享许多相似的特征。由于多态性,一个对象可有独特的表现方式,而另一个对象有另一种表现方式。
5、语言评价(计算机软件专家王汝传 评)
C++语言是对C语言的扩充,从Simula中吸取了类,从ALGOL语言中吸取了运算符的一名多用、引用和在分程序中任何位置均可说明变量,综合了Ada语言的类属和Clu语言的模块特点,形成了抽象类,从Ada Clu和ML等语言吸取了异常处理,从BCPL语言中吸取了用//表示注释C++语言保持了C语言的紧凑灵活、高效以及易于移植性强等优点,它对数据抽象的支持主要在于类概念和机制,对面向对象风范的支持主要通过虚拟机制函数因C++语言既有数据抽象和面向对象能力,运行性能高,加上C语言的普及,而从C语言到C++语言的过渡较为平滑,以及C++语言与C语言的兼容程度可使数量巨大的C语言程序能方便地在C++语言环境中复用,使C++语言在短短几年内能流行。
二、C++与C语言的不同
C++兼容C语言,再次之上开发了许多新的功能,例如:命名空间、类。新的用法:函数重载、缺省值等。
1、IO流
1.1、简介
流是一种抽象概念,它代表了数据的无结构化传递。按照流的方式进行输入输出,数据被当成无结构的字节序或字符序列。从流中取得数据的操作称为提取操作,而向流中添加数据的操作称为插入操作。用来进行输入输出操作的流就称为IO流。换句话说,IO流就是以流的方式进行输入输出。
也就是说,在C++输入和输出的方法有所改进。
1.2、举例
那么回到常规套路,计算机的第一个程序:
#include <iostream>
using namespace std;
int main()
{
cout<<"hello world"<<endl;//流插入
return 0;
}
该程序的结果和C语言的第一个程序结果相同,都是输出的“hello world”。与众不同的是换成了流插入,插入了“hello world”和“endl”。这里的“endl”相当于C语言中的换行“\n”。
1.3、相比于原来输出形式的优点
(1)简明与可读性
IO流类库用IO运算符(提取运算符>>和插入运算符<<)代替了不同的输入输出函数名,如printf和scanf等。从直观来看,这种改变使得IO语句更为简明。另外,也减轻了程序员在记忆函数名和书写程序上的一些负担。例如:
// 1、printf(“n=%d,a=%f\n”,n,a);
// 2、cout<<”n=”<<n<<”,a=”<<a<<endl;
虽然两条语句的输出结果是一样的,但是后者更加简明,直观,易写,易读。
(2)类型安全(type safe)
所谓类型安全,是指编译器所理解的数据实体(如变量。指针所指向的数据等)的类型,与实际数据实体的实际类型或对该数据所进行的操作之间保持一致性。在进行IO操作时,编译器将自动检查实参的表达式类型来调用IO流类相应的重载版本的成员函数,来完成输入输出。而采用C的IO函数,必须显示指明操作的数据类型,如采用printf()函数,由于其参数中的数据类型必须由程序员以参数格式%d,%f,%c,%s,容易出错。
(3)易于扩充
C++语言的IO流类库,是建立在类的继承关系、模板和操作符重载等机制的基础上的。把原来C语言中的左、右移位运算符<<和>>,通过运算符重载的方法,定义为插入(输出)和提取(输入)运算符。这就为输入输出功能对于各种用户定义的类型数据的扩充,创造了方便的条件。
2、命名空间
2.1、简介
namespace即“命名空间”,也称“名称空间” 。是许多编程语言使用的一种代码组织的形式,通过命名空间来分类,区别不同的代码功能,避免不同的代码片段(通常由不同的人协同工作或调用已有的代码片段)同时使用时由于不同代码间变量名相同而造成冲突。
2.2、用法
命名空间,相当于将空间分割开,每个空间都是不同的。在不同的空间之中能够存在相同名字的变量,在使用的时候需要指定命名空间找到变量。例如:
#include <iostream>
using namespace std;
namespace lcs
{
int a = 2;
}
int main()
{
int a = 1;
cout << a << endl << lcs::a << endl;
return 0;
}
从上述举例中不难看出虽然a有两个,但是并没有发生错误,这是因为第二个a实在命名空间里去取的,两个变量是分开的。
根据上述例子也正好能够解释两个新的内容:1、指定命名空间的方式就是空间的名字加“::”然后再调用需要变量或者函数的名字。2、如果不使用命名空间,那么和C语言全局变量和局部变量一样,会优先使用局部变量。
2.3、命名空间的展开
using namespace std;
以上代码就是命名空间的展开形式,std表示的是标准库,和C语言中直接使用的标准不同,C++中的标准库内容都被封装在std的命名空间里面。所以使用的时候需要指定命名空间。如果没有这一句话,想要调用输入或者输出这样的标准库函数就需要为他们指定命名空间。这就是为什么有一些代码里会有“std::”。
std::cout << "hello world" << endl;
展开命名空间之后,就相当于把命名空间的内容放到了静态区,那么命名空间对于代码的保护、分割效果也就消失了,会更容易冲突。所以再工作中,一般不会展开命名空间,代码的结合性提高了。
当然,自己写的短代码就能展开了,因为重复的概率不大。
命名空间的特点之中也包含了嵌套性,也就是说同一命名空间下还能继续分成不同的命名空间。
3、函数的缺省值
3.1、简介
缺省值,对于C++来说,表示函数在没有获得参数时会自动填充的默认参数。这么解释大概一听就能懂,但是用法上有需要主意的点,接下来将通过举例讲解。
3.2、举例
函数的缺省值又是C++的一大进步,它能够在不给实参的时候调用参数的默认值。例如:
int Add(int x = 1, int y = 9)
{
return x + y;
}
int main()
{
int add = Add();
cout << add << endl;
return 0;
}
在Add函数中,我们可以直接调用它而不需要增加参数,就能把值赋给add,当然也可以赋值,例如:
int main()
{
int add = Add();
int add2 = Add(20);
int add3 = Add(13, 36);
cout << add << endl;
cout << add2 << endl;
cout << add3 << endl;
return 0;
}
这里的add2、add3分别会等于29、49,在函数中所给的实参会优先给最左边有缺省值的变量,因此不会出现其他的结果。正应为如此也就有了半缺省的用法,以及规则。缺省值只能有函数参数的右边向左边连续给出,不能间断,也不能改变方向从左向右。一下例子均无法被编译器编译:
void Func(int a = 20, int b, int c = 10)
{}
void Func2(int a = 20, int b = 10, int c)
{}
上述代码的结果是:
根据这个例子,想必大家对函数的缺省值有了一个大致的了解。
4、函数重载
4.1、简介
函数重载是C++中出现的概念,目的是为了解决C语言中函数重名,但作用相同不好命名的问题。那么现在参数的类型也会作为识别函数的内容。
重载函数是函数的一种特殊情况,为方便使用,C++允许在同一范围中声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同,也就是说用同一个函数完成不同的功能。这就是重载函数。重载函数常用来实现功能类似而所处理的数据类型不同的问题。不能只有函数返回值类型不同。
4.2、举例
原来C语言不能出现的函数名相同,现在终于可以相同了,只要参数类型不同就会被区分开:
int Add(int x, int y)
{
return x + y;
}
double Add(double x, double y)
{
return x + y;
}
int main()
{
int add = Add(1, 2);
double add2 = Add(1.11, 2.22);
cout << add << endl;
cout << add2 << endl;
return 0;
}
因为两个函数的参数类型,一个是double,一个是int。编译器会认为这是两个不同的函数,所以会选择合适的那个进行链接,结果为:
这是应为编译器在识别函数的时候会自动将变量类型添加到函数名中,而且顺序不同,也可以,例如:
void Func(int a, char b)
{}
void Func(char a, int b)
{}
值得注意的是返回值并不像参数那样作为重载函数的识别内容。可能祖师爷在想的时候,觉得函数入口作为识别对象更加简单些吧,所以一下函数是不能构成重载的:
int Func(int a, char b)
{
return 1;
}
double Func(int a, char b)
{
return 1.11;
}
结语
资料来源于百度百科,有部分自写的内容,自己的理解。学到这里都算是理解性的知识,实操具体的题目比较少。
下一篇会介绍C++的引用、模版、类和对象等非常实用的内容,可以说非常新鲜。