从C++看编程语言发展脉络

本文涉及的产品
实时计算 Flink 版,5000CU*H 3个月
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
大数据开发治理平台 DataWorks,不限时长
简介: 【5月更文挑战第1天】自1979年以来C++历经40年发展,以其复杂语法影响了Go、Rust和Zig等语言。 回顾C++11,引入了范围for循环、Lambda表达式、自动类型推导、统一初始化、删除和默认函数、nullptr、委托构造器、右值引用、新标准库如线程支持及算法等。C++持续演进,保持其在编程语言中的影响力。

1 简介

C++自1979年首次实现带有类的C以来,已经存在了40年。

现在其C++ 的语法已经非常复杂。

其发展路径具有重要的参考意义,特别是像go,rust这样的类似的语言。

Rust从C++中学到了内存安全的重要性,Zig从C中选择了更细分的内存分配,Go则带上“指针”和“垃圾收集”两件法宝自成一派。

而其C++26已经在规划之中...
也就是 2026年将要发布的版本。

对于C++26,将努力在该标准中具有以下内容:

    * 执行
    * 代码范围
    * 反射

在没有特定场景的情况下,将优化

  • 合约

    Contracts 类似 assert 和 static_assert 的语法,可以在函数声明时使用。

  • 模式匹配

经常说C++需要像它这样的新控制语句头上需要一孔,图案匹配显示很多希望 提供比我们所能提供的更好的 过滤器/链/选择 近似于纯图书馆设施。

模式匹配 通过以下方式提高类型安全性 使编写类型安全代码比编写 传统的 C 型或传统的C++式替代品更好。
此外,它还将访问者置于 在许多情况下,模式。
这不仅仅是另一个控件结构;它与类型系统交互。

在这个领域有相当多的工作正在进行中,在 C++26 时间范围内给它播出时间。

如何运送,以及 以什么形式,目前还不完全清楚。

做为一个经典版本,C++ 11 出现了大量新特征,几乎成为一个新语言。

这里主要回顾C++11的新的特征。包括新的算法,新的容器类原子操作,类型特征,正则表达式,新的智能指针,async()功能多线程库。

 C++11 延迟,
 C++14 准时,
 C++17 准时 ,
 C++20 准时, 
 C++23 将准时,
 C++26 将按时

而C++曾经也是一位昂扬向上的少年,现在只不过是经历了40年之久青年。

1 c++11更新

1.0,基于范围的for循环

int nArr[5] = {1,2,3,4,5};
for(int &x:nArr){
    x *=2; //数组每个元素倍乘
}

1.1,Lambda表达式

允许定义本地功能, 消除大部分乏味而且有安全风险的函数对象。

[capture](parameters)->return-type{body}

[]指示lambda表达式的开始

int main()
{
    char s [] = "hi";
    int Uppercase = 0;
    for_each(s, s+sizeof(s), [&Uppercase] (char c)){
        if (isupper(c))
          Uppercase++;
    });
   cout<< Uppercase<<"uppercase letters in:" << s<<end1;
}

类似与定义一个函数,将其主主体放置在另一个函数调用。[&Uppercase] &表示lambda主体获得对Uppercase的引用,如果没有&,

大写字母将按值传递,C++11 lambda也包括用于成员函数的构造。

1.2,自动类型推导 decltype, Automatic Type Deduction

编译器自动推断i为int类型

    auto i = 1; 

在v11 之前C++ 在声音对象时 必须指定对象类型,很多情况下,对象的声明包括初始化程序, C++11充分利用了这一点,可用在不指定对象类型的情况下声明对象。

auto x=0; //x has type int because 0 is int
auto c='a'; //char
auto d=0.5; //double
auto national_debt=14400000000000LL;//long long

auto不再指定具有自动存储类型的对象。相反,它声明一个对象,该对象的类型可从其初始值设定项推导, 声明一个迭代器

auto ci=vi.begin();

标准模板库容器的判断

  vector<int> vec(6,10);
  vector<int>::iterator iter=vec.iterator();
  auto iterAuto = vec.iterator(); //相比较更方便

1.3,统一初始化语法

C++ 11 使用统一的大括号表示初始化

    std::string s("hello");
    int m=int(); //默认初始化 default initialization

在某些情况下,可用将 = 用于相同目的

    std::string s="hello";
    int x=5;

对于POD聚合,使用花括号

int arr [4] = {0,1,2,3};
today struct tm = {0};

最后构造函数使用成员初始化程序

structs {
    int x;
    s():x(0) {}};
}

1.4,删除函数 和 默认函数

默认函数

struct A {
    A()=default; // C++11 only 指示编译器生成该函数的默认实现
    public: C();
};

默认函数有两个优点:它们比手动实现更有效,并且使程序员摆脱了手动定义这些函数的麻烦。

删除函数

int func()=delete;

已删除的函数对于防止对象复制很有用

    =delete:

    struct NoCopy
    {

     NoCopy & operator =( const NoCopy & ) = delete;

     NoCopy ( const NoCopy & ) = delete;

    };

    NoCopy a;

复制出错

    NoCopy b(a); //compilation error, copy ctor is deleted

1.5,nullptr

一个关键字,它指定空指针常量。

nullptr替换了NULL多年来容易被用作空指针替代的易于出错的宏和立即数0(macro and the literal)。nullptr是强类型的

void f(int); //#1
void f(char *);//#2
//C++03
f(0); //which f is called?
//C++11
f(nullptr) //unambiguous, calls #2

nullptr 适用于所有指针类别,包括函数指针和成员指针

const char *pc=str.c_str(); //data pointers
if (pc!=nullptr)
  cout<<pc<<endl;
int (A::*pmf)()=nullptr; //pointer to member function
void (*pmf)()=nullptr; //pointer to function

1.6,委托建造者 Delegating Constructors

C++11 中构造函数可调用同一类的另一个构造函数

    class M //C++11 delegating constructors
    {int x, y;
     char *p;
     public:
     M(int v) : x(v), y(0), p(new char [MAX]) {} //#1 target
     M(): M(0) {cout<<"delegating ctor"<<endl;} //#2 delegating };

委托构造器#2调用目标构造器#1

1.7, 右值参考

C ++ 03中的引用类型只能绑定到左值。C ++ 11引入了新的引用类型类别,称为rvalue引用。

右值引用可以绑定到右值,例如临时对象和文字

    void naiveswap(string &a, string & b)
    {string temp = a;
     a=b;
     b=temp; }

以上例子需要分配内存,使用右值引用可不分配内存,效率更高

void naiveswap(string &a, string & b)
{

伪代码

 size_t sz = empty.size();
 const char * p = empty.data();

将填充的资源移为空

 empty.setsize(filled.size());
 empty.setdata(filled.data());

填充为空

 fill.setsize(sz);
 fill.setdata(p);
}

1.8,新增标准库

TR1标准包括新的容器类

unordered_set, onordered_map,onordered_multiset, nordered_multimap

正则表达式,元组,功能对象包装,文档库

1.8.1,线程库 并发

promise 和 futures 线程类,在并发环境中用于同步的对象
用于启动并发任务的async()
声明线程tread_local存储类型

1.8.2 新的算法

可模仿集合理论运算的新算法 all_of()

none_of()
ispositive() 范围[first,first+n]

并使用all_of(), any_of()

#include <algorithm>

C ++ 11代码,所有元素都是积极的吗?

all_of(first,first + n,ispositive()); //假

至少有一个积极因素?

any_of(first,first + n,ispositive()); //真

这些元素都不是积极的吗?

none_of(first,first + n,ispositive()); //假

复制数组copy_n()

    #include
    int source [5] = {0,12,34,50,80};
    int target[5];
    // copy 5 elements from source to target
    copy_n(source, 5, target);

iota()创建一系列按顺序递增的值,就像通过将初始值分配给*first

然后使用 ++ 前缀递增该值。 下例中 iota()将连续值{10,11,12,13,14}分配给数组arr,并将{'a', 'b' 'c'} 分配给 char数组

include <numeric>
int a[5]={0};
char c[3]={0};
iota(a, a+5, 10); //changes a to {10,11,12,13,14}
iota(c, c+3, 'a'); //{'a','b','c'}

1.9, 后置返回类型 tailng-return-type

template Ret adding_func(const Lhs &lhs, Const Rhs &rhs){return lhs + rhs;}

C++11的合法语法,添加后置返回类型

template auto adding_func(const Lhs &lhs, const Rhs &rhs) -> decltype(lhs+rhs) {return lhs + rhs;}

更普遍的函数声明和定义

struct SomeStruct {
    auto func_name(int x, int y) -> int;
};
auto SomeStruct::func_name(int x, int y) -> {
    return x + y;
}

1.10, 显示重写 override final

struct Base{
    virtual void some_func(float);
};
struct Derived:Base{
    virtual void somt_func(int) override; // 错误,不会重写基类方法
};

override 编译器将检查基类中有没有一个具有相同签名的虚函数
final用于防止基类被继承和防止子类重写

    struct Base1 final { };
struct Derived1 : Base1 { }; // 病态的, 因为类Base1被标记为final了
struct Base2 {
    virtual void f() final;
};
struct Derived2 : Base2 {
    void f(); // 病态的, 因为虚函数Base2::f 被标记为final了.
};
  • 最大整型

    long long int

1.11, 允许sizeof运算符可用在类型数据成员使用,无需明确对象

struct p {otherClass member;};
sizeof(p:member);

1.12, 元组 tuple

由预先确定数量的多种对象组成,元组可用看作时struct数据成员泛化。

使用可变参数模板,元组的定义时这样的

template <class ...Types> class tuple;

下面是定义和使用元组的一个例子:

typedef std::tuple <int, double, long &, const char *> test_tuple;
long lengthy = 12;
test_tuple proof (18, 6.5, lengthy, "Ciao!");
lengthy = std::get<0>(proof);  // 把'lengthy' 赋值为18.
std::get<3>(proof) = " Beautiful!";  // 修改元组的第四个元素

1.13,常量constexpr

保证函数或者对象构造函数在编译器常量

constexpr int GetFive() {return 5;}
int some_value[GetFive() + 7];

產生12個整數的陣列。合法的C++11寫法

2 小结

自2011年C++标准的重大修正以来,2020年的C++20被称为又一个里程碑。 而C++26也在计划之中。

C++一般被人认为是C的超集,但是这并不完全准确。

相比C语言,C++早期的新功能就包括

类,成员函数,派生类,单独的编译,
公共和私有访问控制,友元,函数参数的类型检查,默认参数,内联函数,重载运算符,
构造函数,析构函数,调用和返回函数,并发库,虚函数,复数,
引用,命名空间,异常处理,模板,容器,IO流等。

C++20更引入了检查程序实体,例如检查变量,枚举,类及其成员,lambda及其捕获功能等。

大部分C语言代码可以很轻易地在C++正确编译,但是仍有少数差异,导致某些有效C代码在C++失效。

如果需要混用它们,则需要在C++中调用,必须放在 extern "C"{/C代码/}内。

参考

https://en.wikipedia.org/wiki/C++11

https://www.open-std.org/
目录
相关文章
|
20天前
|
算法 程序员 编译器
C++与C语言的差异:编程语言之间的奥秘探索
C++与C语言的差异:编程语言之间的奥秘探索
54 0
|
20天前
|
存储 算法 搜索推荐
在C++编程语言中数组的作用类型
在C++编程语言中数组的作用类型
17 0
在C++编程语言中数组的作用类型
|
20天前
|
存储 程序员 C++
在C++编程语言中指针的作用类型
在C++编程语言中指针的作用类型
19 0
|
20天前
|
机器学习/深度学习 开发框架 人工智能
探索C++的深邃世界:编程语言的魅力与实践
探索C++的深邃世界:编程语言的魅力与实践
|
9月前
|
Java 程序员 Apache
编程语言比拼之Java VS C++
Java和C++都是非常受欢迎的编程语言,各有各的优势和适用场景。以下是对它们的简要比较:
|
20天前
|
编解码 JavaScript 前端开发
【专栏】介绍了字符串Base64编解码的基本原理和在Java、Python、C++、JavaScript及Go等编程语言中的实现示例
【4月更文挑战第29天】本文介绍了字符串Base64编解码的基本原理和在Java、Python、C++、JavaScript及Go等编程语言中的实现示例。Base64编码将24位二进制数据转换为32位可打印字符,用“=”作填充。文中展示了各语言的编码解码代码,帮助开发者理解并应用于实际项目。
|
20天前
|
安全 编译器 C语言
C++:编程语言中的强大工具
C++:编程语言中的强大工具
15 0
|
20天前
|
安全 vr&ar C++
C++:编程语言的演变、应用与最佳实践
C++:编程语言的演变、应用与最佳实践
|
20天前
|
开发框架 Java .NET
C#编程语言的优势与C++对比
C#编程语言的优势与C++对比
|
20天前
|
Linux C语言 C++
C++编程语言简介及其应用
C++编程语言简介及其应用
17 0