ModernC++的一些特性


Modern C++

Modern C++指的是C++11/C++14/C++17/C++20等版本,新增和改进了C++语法,提升开发效率.

nullptr

nullptr是用来替换NULL的

constexpr

常量表达式

constexpr int num = 1 + 2+ 3;

if/switch 变量声明强化

    if (int i = num - 1){

    }

即判断条件中可以直接声明临时变量.

初始化列表

#include <iostream>
#include <string>

using namespace std;

class Person {
public:
    string name;
    int age;
    int sex;

    const string &getName() const {
        return name;
    }

    int getAge() const {
        return age;
    }

    int getSex() const {
        return sex;
    }
};


void testInit() {
    Person person = {"jack", 18, 1};
}

C++11之前的版本初始化比较麻烦,需要写一些无用代码,这之后比较灵活,可以按照上面的方式进行初始化.

结构化绑定

即多返回值的封包/拆包,在Python,Go,Kotlin中比较常见.

#include <iostream>
#include <tuple>

using namespace std;

void testTuple() {
    auto[x, y, z] = make_tuple(1, false, "hello");
    cout << x << y << z << endl;
}

auto

即类型推断,不用每个变量声明都声明类型.

需要注意的就是:auto不能用于函数传参,也不能用于推导数组类型

decltype

auto只能用于变量的类型推断,decltype则对表达式类型推断做了补充.

auto x = 1;
auto y = 2;
decltype(x+y) z;

区间for迭代

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {1, 2, 3, 4};
    if (auto itr = std::find(vec.begin(), vec.end(), 3); itr != vec.end()) *itr = 4;
    for (auto element : vec)
        std::cout << element << std::endl; // read only
    for (auto &element : vec) {
        element += 1;                      // writeable
    }
    for (auto element : vec)
        std::cout << element << std::endl; // read only
}

模板

将一切能在编译期解决的问题放在编译期解决,仅在运行时处理核心的动态服务.

外部模板

template class std::vector<bool>;          // 强行实例化
extern template class std::vector<double>; // 不在该当前编译文件中实例化模板

其实就是一个实例化时机的问题.

类型别名模板

模板是用来生成类型的.

类型别名一般这样用:

typedef 原名称 新名称

对于复杂一点的就显得很难看,可以使用using:

typedef int (*process)(void *);
using NewProcess = int(*)(void *);
template<typename T>
using TrueDarkMagic = MagicType<std::vector<T>, std::string>;

int main() {
    TrueDarkMagic<bool> you;
}

委托构造

#include <iostream>
class Base {
public:
    int value1;
    int value2;
    Base() {
        value1 = 1;
    }
    Base(int value) : Base() { // 委托 Base() 构造函数
        value2 = value;
    }
};

int main() {
    Base b(2);
    std::cout << b.value1 << std::endl;
    std::cout << b.value2 << std::endl;
}

没什么好说的,其他语言在设计的时候就已经支持了.

继承构造

#include <iostream>
class Base {
public:
    int value1;
    int value2;
    Base() {
        value1 = 1;
    }
    Base(int value) : Base() { // 委托 Base() 构造函数
        value2 = value;
    }
};
class Subclass : public Base {
public:
    using Base::Base; // 继承构造
};
int main() {
    Subclass s(3);
    std::cout << s.value1 << std::endl;
    std::cout << s.value2 << std::endl;
}

overide , final

struct Base {
    virtual void foo(int);
};
struct SubClass: Base {
    virtual void foo(int) override; // 合法
    virtual void foo(float) override; // 非法, 父类没有此虚函数
};
struct Base {
    virtual void foo() final;
};
struct SubClass1 final: Base {
}; // 合法

struct SubClass2 : SubClass1 {
}; // 非法, SubClass1 已 final

struct SubClass3: Base {
    void foo(); // 非法, foo 已 final
};

这两点也没什么好说的,其他语言早就支持了.

Lambda

[捕获列表](参数列表) mutable(可选) 异常属性 -> 返回类型 {
// 函数体
}

值捕获

void lambda_value_capture() {
    int value = 1;
    auto copy_value = [value] {
        return value;
    };
    value = 100;
    auto stored_value = copy_value();
    std::cout << "stored_value = " << stored_value << std::endl;
    // 这时, stored_value == 1, 而 value == 100.
    // 因为 copy_value 在创建时就保存了一份 value 的拷贝
}

引用捕获

void lambda_reference_capture() {
    int value = 1;
    auto copy_value = [&value] {
        return value;
    };
    value = 100;
    auto stored_value = copy_value();
    std::cout << "stored_value = " << stored_value << std::endl;
    // 这时, stored_value == 100, value == 100.
    // 因为 copy_value 保存的是引用
}

范型Lambda

auto add = [](auto x, auto y) {
    return x+y;
};

add(1, 2);
add(1.1, 2.2);

函数对象包装器

如果不使用std::fucntion()是这样子的:

#include <iostream>

using foo = void(int); // 定义函数类型, using 的使用见上一节中的别名语法
void functional(foo f) { // 定义在参数列表中的函数类型 foo 被视为退化后的函数指针类型 foo*
    f(1); // 通过函数指针调用函数
}

int main() {
    auto f = [](int value) {
        std::cout << value << std::endl;
    };
    functional(f); // 传递闭包对象,隐式转换为 foo* 类型的函数指针值
    f(1); // lambda 表达式调用
    return 0;
}

使用了之后是这样的:

#include <functional>
#include <iostream>

int foo(int para) {
    return para;
}

int main() {
    // std::function 包装了一个返回值为 int, 参数为 int 的函数
    std::function<int(int)> func = foo;

    int important = 10;
    std::function<int(int)> func2 = [&](int value) -> int {
        return 1+value+important;
    };
    std::cout << func(10) << std::endl;
    std::cout << func2(10) << std::endl;
}

文章作者: 姜康
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 姜康 !
评论
  目录