1、nullptr
void foo(char *); void foo(int);
foo(NULL) //编译出错,不知道调用哪个,可能调用了foo(int)
foo(nullptr) //ok ,调用foo(char*)
//用nullptr替换原先的NULL
2、constexpr
#define LEN 10 int len_foo() { return 5; } int main() { char arr_1[10]; char arr_2[LEN]; int len = 5; char arr_3[len+5]; // 非法 const int len_2 = 10; char arr_4[len_2+5]; // 合法 char arr_5[len_foo()+5]; // 非法 return 0; } 改成:constexpr int len_foo() { return 5; } constexpr int len = 5;
3、auto 与 decltype用于类型推导
// 由于 cbegin() 将返回 vector<int>::const_iterator
// 所以 itr 也应该是 vector<int>::const_iterator 类型
for(auto itr = vec.cbegin(); itr != vec.cend(); ++itr);
auto x = 1; auto y = 2; decltype(x+y) z;
4、基于范围的for循环
int array[] = {1,2,3,4,5}; for(auto &x : array) { std::cout << x << std::endl; }
5、using的新用法,using可以替换typedef,可读性更好,也更灵活
template <typename T,typename U,int value> class SuckType { public: T a; U b; SuckType():a(value),b(value){} }; template <typename U> using NewType = SuckType<int, U, 1>; //typedef不支持模板推导 using Process = int(*)(void*); // 等效于 typedef int(*Process)(void*);
6、override,final关键字,override显示表明子类需要重载父类的方法,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 { }; // 非法, SubClass 已 final
struct SubClass3: Base { void foo(); // 非法, foo 已 final };
7、委托构造函数与继承构造
//委托构造 class Base { public: int value1; int value2; Base(){ value1 = 1; } Base(int value) :Base() { value2 = value; } virtual void foo(int) {}; }; class Sub : public Base { public: using Base::Base;//继承构造 };
8、enum增强
enum class new_enum :unsigned int { value1, value2, value3=100, value4, value5=100 }; int main(int argc, const char *argv[]) { if (new_enum::value3 == new_enum::value5) { cout << "equal" << endl; } if (static_cast<int>(new_enum::value1) == 0) { cout << "equal" << endl; } if (new_enum::value2 == 1) //编译报错 { cout << "equal" << endl; } if (new_enum::value4==static_cast<new_enum>(1)) { cout << "equal" << endl; } }
9、可变参数模板,初始化列表,这个有点复杂,建议再找相关文档学习
template<class T> T sum(T & t) { return t; } template<class T,class ... Args> T sum(T t, Args... rest) { return t + sum<T>(rest...); } template<class T=int> class FooVector { public: using l = initializer_list<T>; std::vector<T> m_ve; FooVector(const l &list) { for (auto &x : list) { m_ve.push_back(x); } } void print() { for (auto &x : m_ve) { cout << x << endl; } } }; int main(int argc, const char *argv[]) {
sum(1,2,3,6,7); FooVector<> a{ 1,2,3,4 }; a.print(); }
10、lambda表达式
[...] (...) ... {...}
[] 内是一个capture,可以在lambda内部访问的"nonstatic外部变量",如果没有要访问的变量,可以为空。static变量是可以直接被访问的。
() 内是参数,和函数参数一样。
... 是mutable, 异常明细, 属性说明符(noexcept等), 或者返回类型。如果其中之一出现,那么必须出现()。
{} 内是函数体,在这里面写明lambda要完成的工作。
[](){cout << "hello world"; }(); //[] 空捕获列表 //[name1, name2, ...] 捕获一系列变量 //[&] 引用捕获, 让编译器自行推导捕获列表 //[=] 值捕获, 让编译器执行推导应用列表 int x=10,y=20; auto f = [&](int a) -> int { cout << "hello, world " << a <<x<<y++<< endl; return a; }; cout<<y;
11、std::function与std::bind
int foo(int a, int b, int c) { ; } int main() { // 将参数1,2绑定到函数 foo 上,但是使用 std::placeholders::_1 来对第一个参数进行占位
std::function<int(int,int,int)> f = foo;
f(1,2,3);
auto bindFoo = std::bind(foo, std::placeholders::_1, 1,2); // 这时调用 bindFoo 时,只需要提供第一个参数即可 bindFoo(1); }