美文网首页我爱编程程序员
C++ 不是 C 的一个超集:C++ 11 特性

C++ 不是 C 的一个超集:C++ 11 特性

作者: 一名普通用户 | 来源:发表于2017-09-12 17:28 被阅读0次

    这是很久之前的笔记,整理发出来并加了一点更新。

    虽然C程序能用C++编译器编译,但是严格来说,C++ 不是 C 的一个超集。《为什么说C++不是C的超集? - 知乎》 这里有网友的解答,不再赘述。

    C 和 C++ 混合使用的例子

    // foo.h
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    int add(int x, int y);
    
    #ifdef __cplusplus
    }
    #endif
    
    // foo.c
    int add(int x, int y) {
        return x+y;
    }
    
    // main.cpp
    #include "foo.h"
    int main() {
        add(1, 2);
        return 0;
    }
    

    编译的命令是

    gcc -c foo.c
    g++ main.cpp foo.o -o main
    

    C++ 中的 C++ 11 特性

    一份个人的笔记,不是完整版,仅供参考

    • C++11 引入了 nullptr 关键字,专门用来区分空指针、0。nullptr 的类型为 nullptr_t

    • constexpr是限定了修饰的为编译期间可确定的常量,但是constexpr也是可以用于函数的,

    constexpr int fibonacci(const int n) {
        return n == 1 || n == 2 ? 1 : fibonacci(n-1)+fibonacci(n-2);
    }
    

    Clang在处理constexpr时,在编译期间用一个C++的计算器计算constexpr的值,并且记录计算的次数。当次数超过一定值时,这个constexpr退化为非constexpr。

    • 使用 auto 进行类型推导的一个最为常见而且显著的例子就是迭代器。
      for(vector<int>::const_iterator itr = vec.cbegin(); itr != vec.cend(); ++itr)
      for(auto itr = vec.cbegin(); itr != vec.cend(); ++itr)
      auto不能用于函数传参,因此下面的做法是无法通过编译的(考虑重载的问题,我们应该使用模板),auto 还不能用于推导数组类型:int arr[10] = {0},auto a[10] = arr
    int array[] = {1,2,3,4,5};
    for(auto &x : array) {
        std::cout << x << std::endl;
    }
    //& 启用了引用, 如果没有则对 arr 中的元素只能读取不能修改,不加却又修改不会报错。
    
    • decltype 声明某种类型
    auto x = 1;
    auto y = 2;
    decltype(x+y) z;
    

    尾置返回允许我们我们在参数列表后声明返回类型

    template<T>
    auto f(T a,T b) -> decltype(*a)
    {
      return *a;
    }
    
    • int a[3] = {1,2,3} 列表初始化
    struct A {
        int a;
        float b;
    };
    struct B {
    
        B(int _a, float _b): a(_a), b(_b) {}
    private:
        int a;
        float b;
    };
    A a {1, 1.1};    // 统一的初始化语法
    B b {2, 2.2};
    
    • std::initializer_list,允许构造函数或其他函数像参数一样使用初始化列表,
    #include <iostream>
    #include <initializer_list>
    
    using namespace std;
    
    int f(initializer_list<int> list)
    {
        int ans = 0;
        for(auto i : list)
            ans += i;
        return ans;
    }
    cout<<f({1,2,3});
    
    • C++11 开始,连续的右尖括号将变得合法,并且能够顺利通过编译。
    typedef int (*process)(void *);  //
    定义了一个返回类型为 int,参数为 void* 的函数指针类型,名字叫做 process
    using process = int(*)(void *);
    // 同上, 更加直观
    template <typename T>
    using NewType = SuckType<int, T, 1>; // 合法
    
    • 默认模板参数
    template<typename T=int, typename U=int>
    auto add(T x, U y) {
        return x+y;
    }
    
    • 委托构造
    class Base {
    public:
        int v1,v2;
        Base() {
            v1 = 1;
        }
        Base(int value) : Base()  {  //成员初始化列表 委托 Base() 构造函数
            v2 = 2;
        }
        Base(int value) {  // 委托 Base() 构造函数
            Base();
            v2 = 2;
        }
    };
    
    • 继承构造
    class Test : public Base{
        public:
        test() {
            using Base::Base; // 继承构造
        }
    }
    
    • 引入 override 关键字将显式的告知编译器进行重载,编译器将检查基函数是否存在这样的虚函数,否则将无法通过编译:
    struct Base {
        virtual void foo(int);
    };
    struct SubClass: Base {
        virtual void foo(int) override; // 合法
        virtual void foo(float) override; // 非法, 父类没有此虚函数
    };
    

    final 则是为了防止类被继续继承以及终止虚函数继续重载引入的。

    struct Base {
            virtual void foo() final;
    };
    struct SubClass1 final: Base {
    };                  // 合法
    
    struct SubClass2 : SubClass1 {
    };                  // 非法, SubClass 已 final
    
    struct SubClass3: Base {
            void foo(); // 非法, foo 已 final
    };
    
    • 枚举类 此处默认 unsigned int , 未指定时将默认使用 int
    enum class new_enum : unsigned int {
        value1,
        value2,
        value3 = 100,
        value4 = 100
    };
    
    • 捕获错误
    try{
      //
    }catch(runtime_error e) {
      cout<<e.what()<<endl;
    }
    

    来自个人 C++ 文集

    相关文章

      网友评论

        本文标题:C++ 不是 C 的一个超集:C++ 11 特性

        本文链接:https://www.haomeiwen.com/subject/rgocsxtx.html