0%

C++11知识点

C++11知识点

C++11知识点

const和constexpr

前者修饰常量,后者修饰常量表达式

区别在于前者只是表达只读语义,保证运行时不被修改,但是其修饰的遍历本身仍然可能是个动态变量,而后者所修饰的是真正的常量,会保证在编译期间就计算出来。

特性constconstexpr
计算阶段运行时编译时
初始化要求可运行时初始化必须编译期确定
函数修饰不能修饰函数可修饰函数
内存分配可能需要存储空间可能仅存在于编译期符号表

constexpr修饰函数:只能修饰单语句return的函数,相当于修饰其返回值,这类函数在被调用的时候其返回值会尽可能在编译期确定

#include<iostream>
using namespace std;

constexpr int func(int i) {
return i + 1;
}

int main() {
int i = 2;
func(i);// 普通函数
func(2);// 编译期间就会被计算出来
}

 

function类与反射实现

function

顾名思义,std::function就是用来存储函数的,专业名词称为“多态函数包装器”,可以复制和存储任意可调用的目标:函数、lambda表达式、绑定表达式、指向成员函数和指向数据成员的指针等等。

用法:class function<R(Args...)>

R为函数返回类型、Args为调用函数的形参。

C++简单反射实现:

#include <iostream>
#include <unordered_map>
#include <functional>
class Reflector{
public:
    template<typename Function>
    static void registerFunc(const std::string& name,Function func){
        getRegistery()[name] = func;
    }
    static bool invoke(const str::string& name){
        auto& registry = getRegistry();
        if(registry.find(name)!=registry.end()){
            registry[name]();
            return true;
        }
        return false;
    }
private:
    //全局注册表,用static做线程安全单例
    static auto& getRegistry(){
        static std::unordere_map<std::string,std::function<void()>> registry;
        return registry;
    }
}

void solve() {}

int main(){
Reflector::registerFunc("solve",solve);
Reflector::invoke("solve");
}

函数对象,即仿函数

 

explicit

用于修饰有参构造函数,表明此构造函数是显式而非隐式的

  • 禁止对象间的隐式转换
  • 禁止隐式调用拷贝构造函数

例如:

class Obj{
    Obj(){}
    explicit Obj(int val):_val(val){}
private:
    int _val;    
}

int main(){
Obj obj1(1);
Obj obj2 = 1;//这种方法在有参构造函数被explicit修饰后会报错,因为其中涉及到构造临时对象1拷贝临时对象到对象obj2两步骤
}

 

delete

//略

 

default

显式声明默认构造函数

 

final & override

final用于修饰一个类,表示该类禁止进一步派生

override用于修饰派生类中的成员函数,标明该函数重写了基类函数,如果用override声明了函数但是父类没有对应虚函数则报错。

 

nullptr

//略

 

继承构造函数

即子类继承父类的构造函数。

struct Base {
    Base() {}
    Base(int a) { a_ = a; }
    Base(int a, int b) : Base(a) { b_ = b; }
    Base(int a, int b, int c) : Base(a, b) { c_ = c; }

int a_;
int b_;
int c_;

};

struct Derived : Base {
using Base::Base;
};

 

委托构造函数

同一个类中一个构造函数调用另一个构造函数:

struct A {
    A(){}
    A(int a) { a_ = a; }
    A(int a, int b) : A(a) { b_ = b; }
    A(int a, int b, int c) : A(a, b) { c_ = c; }
    
int a_;
int b_;
int c_;

};

 

并发

//略

 

bind

bind返回一个函数对象,可以放进Funtion类对象中

//以下两种分别代表了bind的两种重载(函数和成员函数)

double callableFunc (double x, double y) {return x/y;}
auto NewCallable = std::bind (callableFunc, std::placeholders::_1,2);

//

class Base
{
public:
void display_sum(int a1, int a2)
{
std::cout << a1 + a2 << '\n';
}

int m_data = 30;

};
int main()
{
Base base;
auto newiFunc = std::bind(&Base::display_sum, &base, 100, std::placeholders::_1);
newiFunc(20); // should out put 120.
}

 

列表初始化

//略

 

左值右值

//略

 

auto & decltype

auto类型即编译器来编译期就推导出来的类型,用于推导变量类型

decltype用于推导表达式类型

auto a = 10;
const int& i = 1;
int a = 2;
decltype(i) b = 2;

 

enum class

带作用域的枚举。

原来的枚举是自动转换成整型的,所以不同枚举之间可以进行比较,例如枚举A的第一个值和枚举B的第一个值相等,容易出现隐性bug。

使用带作用域的枚举,不同枚举之间比较会出现编译错误。而且此枚举可以手动选择底层类型。