C++11知识点
const和constexpr
前者修饰常量,后者修饰常量表达式
区别在于前者只是表达只读语义,保证运行时不被修改,但是其修饰的遍历本身仍然可能是个动态变量,而后者所修饰的是真正的常量,会保证在编译期间就计算出来。
特性 | const | constexpr |
---|---|---|
计算阶段 | 运行时 | 编译时 |
初始化要求 | 可运行时初始化 | 必须编译期确定 |
函数修饰 | 不能修饰函数 | 可修饰函数 |
内存分配 | 可能需要存储空间 | 可能仅存在于编译期符号表 |
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。
使用带作用域的枚举,不同枚举之间比较会出现编译错误。而且此枚举可以手动选择底层类型。