C++11新特性(三):语言特性

C++11新特性

范围for循环

std::vector<int> nums;
for (auto it : nums){
    cout << *it << endl;
}
array<5, int> a{1, 2, 3 ,4 ,5};
for (auto x : a){
    x *= 2; // 此时a中元素不会发生改变a{1, 2, 3, 4, 4}
}
for (auto& x : a){
    x *= 2; // 此时a中元素会发生改变a{2, 4, 6, 8, 8}
}
for_each(a.begin(), a.end(), [](int x){x*=2;}) // a中元素不会发生改变

移动语义特殊成员函数

参见st::move()实现移动构造函数和移动赋值运算符

转换构造器

转换构造器支持花括号列表语义到参数的转换

class MyClass{
pulic:
    MyClass(int){}
    MyClass(int, int){}
};
MyClass b{1,2};

显式转换函数

explict可用于类构造器和运算符中禁止隐式转换,比如禁止基础数据类型直接隐式转换为类对象。

class MyClass{
     explict MyClass(int){
    	/* code */
	}  
};
void Func(MyClass a){
    
}
MyClass a(1.1); // OK, 只是float->int的隐式转换,不涉及到类对象的转换,此时是可行的。
Func(1.1); // Error, 此时会涉及float->MyClass的隐式转换,但是由于explict声明会拒绝隐式类型转换
Func(MyClass(1.1)); // OK, 显示指明转换类型

内联命名空间

内联空间可以使该空间像是父空间的一部分。

namespace Parent{
    namespace Cousin{
        void GetCousinName(){}
    }
    inline namespace Son{
        void GetSonName(){}
    }
}
Parent::Cousin::GetCousinName(); // 嵌套的命名空间的作用域在嵌套作用域中,也是侄子有私人空间
Parent::GetSonName(); // 内联命名空间作用域在父空间中,儿子没有私人空间。
using Parent::Cousin::GetCousinName; // 导入命名空间中的函数
GetCousinName();
namespace cousin = Parent::Cousin; //命名空间别名

非静态数据成员初始化

C++11允许非静态成员初始化。

class Cat{
    Cat(int a) : val(a){}
    int val = 0; // 允许非静态成员直接初始化
    int name {0};
};

右角括号

map<map<int, int>>; // C++11才支持可以无空格连续右角括号

引用限定成员函数

引用限定成员函数能够检查对象的*this是一个左值引用还是右值引用

class Cat{
public:
    Cat(int a) : val(a){}
    void GetName() &{
        cout << "lvalue" << endl;
    }
    void GetName() &&{
        cout << "rvalue" << endl;
    }
private:
    int val = 0; // 允许非静态成员直接初始化
    int name {10};
};
int main()
{
    Cat s(5);
    s.GetName(); // 左值调用GetName() &
    move(s).GetName(); // 右值引用调用GetName() && 
    Cat&& m = move(s);
    m.GetName(); // lvalue,此时就会出现右值传入时会退化为左值
}

尾部返回类型

允许使用->来为lambda和不明确函数返回类型指定返回类型。

auto Func1() -> int{
    /* code */
}
auto Func2 = []() -> int{};

noexcept限定符

noexcept关键字告诉编译器该函数不会抛出任何异常,从而允许编译器优化。如果抛出了异常,会用std::terminate终止程序运行。可以省略一些编译器生成一些异常处理代码。可以是条件性判断抛出异常。noexcept常用于修饰需要更改资源访问的函数,比如默认构造函数、析构函数、移动构造函数、移动赋值运算符、拷贝构造函数、拷贝赋值运算符。

void Add(int a, int b) noexcept{
    // 不会抛出任何异常
}
void AddIf(int a, int b) noexcept(false){
    // 可能会抛出异常
}

char32_t 和char16_t标准类型

char32_t char16_t代表UTF-8字符串(1-4个字节)

原始字面字符串

举例完成对原生字面字符串语法的展现

const char* str = "hello,\nworld\n";
// 等价于
const char* str = R"(hello,
world)";
posted @ 2024-08-24 10:41  LemHou  阅读(54)  评论(0)    收藏  举报