天津建设网站的公司简介,网站的外部链接建设图片,网上做论文的网站,自己怎么建立公司网站c11 1. {}初始化2. 范围for循环3. final与override4. 右值引用4.1 左值引用和右值引用4.2 左值引用与右值引用比较 5. lambda表达式6. 声明6.1 auto6.2 decltype6.3 nullptr 7. 可变参数模版 1. {}初始化
在C中#xff0c;使用花括号初始化的方式被称为列表初始化。列表初始化… c11 1. {}初始化2. 范围for循环3. final与override4. 右值引用4.1 左值引用和右值引用4.2 左值引用与右值引用比较 5. lambda表达式6. 声明6.1 auto6.2 decltype6.3 nullptr 7. 可变参数模版 1. {}初始化
在C中使用花括号初始化的方式被称为列表初始化。列表初始化可以用于数组、结构体、类等类型的初始化。在C11之前列表初始化仅能用于数组和POD类型的初始化。C11新标准将列表初始化应用于所有对象的初始化。以下是一些使用列表初始化的例子
struct Point
{int _x;int _y;
}; class foo
{
public:foo(int i, double d) :_i(i), _d(d) {} // 构造函数
private:int _i;double _d;
};
int main()
{int arr[]{ 1, 2, 3, 4, 5 }; // 数组Point p{ 1,2 }; // 结构体foo f{ 1, 3.14 }; // 类return 0;
}以上代码中arr 是一个整型数组使用列表初始化方式进行了初始化p 是一个结构体使用列表初始化方式对其成员变量进行了初始化f 是一个类对象使用列表初始化方式对其成员变量进行了初始化。
2. 范围for循环
在C中范围for循环是一种用于遍历数组、容器、初始化列表等类型的语法结构。它的语法格式如下
for (declaration : expression)
{// 循环体
}其中declaration 表示遍历声明在遍历过程中当前被遍历到的元素会被存储到声明的变量中。expression 是要遍历的对象它可以是表达式、容器、数组、初始化列表等。
以下是一个使用范围for循环的例子
#include iostream
#include vectorint main()
{std::vectorint v {1, 2, 3, 4, 5};for (auto value : v){std::cout value ;}std::cout std::endl;return 0;
}以上代码中v 是一个整型向量使用范围for循环方式进行了遍历。 需要注意的是在使用范围for循环遍历容器时循环会自动以容器为范围展开并且循环中也屏蔽掉了迭代器的遍历细节直接抽取容器中的元素进行运算使用这种方式进行循环遍历会让编码和维护变得更加简便。
其中还有一个点需要注意上述value相当于一个形参也就是说value改变不影响数组v的改变那么怎么在遍历的时候又能修改数组v其实可以使用引用访问元素如下
#include iostream
#include vectorint main()
{std::vectorint v { 1, 2, 3, 4, 5 };cout 没有使用引用访问:;for (auto value : v){value * 2;}for (auto value : v){std::cout value ;}std::cout std::endl;cout 使用引用访问:;for (auto value : v){value * 2;}for (auto value : v){std::cout value ;}std::cout std::endl;return 0;
}在C中使用范围for循环时如果使用引用访问元素可以避免对元素进行拷贝从而提高程序的效率。当使用值访问元素时会对元素进行一次拷贝而使用引用访问元素时则不会进行拷贝。因此在不改变元素的情况下使用引用访问元素可以减少一次拷贝提高程序的效率。
3. final与override
在C11中override 和 final 是两个新的关键字用于增强代码的安全性和可读性。
override 用于在派生类中重写基类的虚函数时显式地告诉编译器此函数是重写基类的虚函数。如果重写时函数名、参数列表和返回类型都和基类的虚函数一致但是没有加上 override 关键字那么编译器无法判断是否是故意的重写容易导致程序出错。加上 override 关键字后编译器会在编译时检查是否真的重写了基类的虚函数如果没有则会报错从而避免了这种错误。
final 用于修饰类、函数或者变量表示它们是终态的不能被派生类、重写或者修改。使用 final 关键字可以防止子类再覆写父类的虚函数。如果一个虚函数被声明为 final则派生类不能再重写它。
4. 右值引用
4.1 左值引用和右值引用
什么是左值什么是左值引用 左值是一个表示数据的表达式(如变量名或解引用的指针)我们可以获取它的地址对它赋值左值可以出现赋值符号的左边右值不能出现在赋值符号左边。定义时const修饰符后的左值不能给他赋值但是可以取它的地址。左值引用就是给左值的引用给左值取别名。
int main()
{// 以下的p、b、c、*p都是左值int* p new int(0);int b 1;const int c 2;// 以下几个是对上面左值的左值引用int* rp p;int rb b;const int rc c;int pvalue *p;return 0;
}什么是右值什么是右值引用 右值也是一个表示数据的表达式如字面常量、表达式返回值函数返回值(这个不能是左值引用返回)等等右值可以出现在赋值符号的右边但是不能出现出现在赋值符号的左边右值不能取地址。右值引用就是对右值的引用给右值取别名。
int main()
{double x 1.1, y 2.2;// 以下几个都是常见的右值10;x y;fmin(x, y);// 以下几个都是对右值的右值引用int rr1 10;double rr2 x y;double rr3 fmin(x, y);// 这里编译会报错error C2106: “”: 左操作数必须为左值//10 1;//x y 1;//fmin(x, y) 1;return 0;
}需要注意的是右值是不能取地址的但是给右值取别名后会导致右值被存储到特定位置且可以取到该位置的地址也就是说例如不能取字面量10的地址但是rr1引用后可以对rr1取地址也可以修改rr1。如果不想rr1被修改可以用const int rr1 去引用。
4.2 左值引用与右值引用比较
左值引用是用符号 声明的它只能绑定到左值即可以取地址、有名字、非临时的对象。左值引用可以用来修改或读取所绑定的对象的值。右值引用是用符号 声明的它只能绑定到右值即不能取地址、没有名字、临时的对象。右值引用可以用来延长所绑定的对象的生命周期或者实现移动语义即将对象的资源从一个所有者转移到另一个所有者而不需要进行拷贝。一个例外是const左值引用可以绑定到右值这样可以实现对右值的只读访问而不改变其生命周期。另一个例外是在函数重载时如果有一个参数既可以接受左值引用又可以接受右值引用那么编译器会优先选择左值引用。这是为了避免对左值进行不必要的移动操作。
左值引用和右值引用的优缺点如下
左值引用的优点是可以对所引用的对象进行修改或读取而不需要拷贝或移动。左值引用的缺点是不能绑定到右值如果需要绑定到右值必须使用常量左值引用但这样就不能修改所引用的对象了。右值引用的优点是可以实现移动语义减少拷贝或赋值操作的开销提高程序的效率。右值引用的缺点是不能修改所引用的对象而且会改变所引用对象的状态使其失去资源的所有权。
5. lambda表达式
在C98中如果想要对一个数据集合中的元素进行排序可以使用std::sort方法但是如果排序的是自定义类型元素每次为了实现一个algorithm算法都要重新去写一个类如果每次比较的逻辑不一样还要去实现多个类特别是相同类的命名这些都给编程者带来了极大的不便。因此在C11语法中出现了Lambda表达式。
在C11中Lambda表达式是一种用于定义匿名函数的语法结构。Lambda表达式可以用于任何需要函数对象的地方例如函数参数、返回值、STL算法等。Lambda表达式的语法格式如下
[capture-list] (parameters) mutable - return-type { statement };lambda表达式各部分说明
[capture-list] : 捕捉列表该列表总是出现在lambda函数的开始位置编译器根据[]来判断接下来的代码是否为lambda函数捕捉列表能够捕捉上下文中的变量供lambda函数使用。(parameters)参数列表。与普通函数的参数列表一致如果不需要参数传递则可以连同()一起省略。mutable默认情况下lambda函数总是一个const函数mutable可以取消其常量性。使用该修饰符时参数列表不可省略(即使参数为空)。-returntype返回值类型。用追踪返回类型形式声明函数的返回值类型没有返回值时此部分可省略。返回值类型明确情况下也可省略由编译器对返回类型进行推导。{statement}函数体。在该函数体内除了可以使用其参数外还可以使用所有捕获到的变量。
注意 在lambda函数定义中参数列表和返回值类型都是可选部分而捕捉列表和函数体可以为空。因此C11中最简单的lambda函数为[]{}; 该lambda函数不能做任何事情。
int main()
{// 最简单的lambda表达式, 该lambda表达式没有任何意义[] {};// 省略参数列表和返回值类型返回值类型由编译器推导为intint a 3, b 4;[] {return a 3; };// 省略了返回值类型无返回值类型auto fun1 [](int c) {b a c; };fun1(10);cout a b endl;// 各部分都很完善的lambda函数auto fun2 [, b](int c)-int {return b a c; };cout fun2(10) endl;// 复制捕捉xint x 10;auto add_x [x](int a) mutable { x * 2; return a x; };cout add_x(10) endl;return 0;
}int main()
{int x 10, y 20;auto func1 [](int x 1,int y 2) //当捕捉列表和参数列表都有x,y优先用参数列表中的值。{cout x y endl; // 3};func1();return 0;
}int main()
{int x 0, y 1;int m 0, n 1;auto swap1 [](int rx, int ry){int tmp rx;rx ry;ry tmp;};swap1(x, y);cout x y endl;// 引用捕捉auto swap2 [x, y](){int tmp x;x y;y tmp;};swap2();cout x y endl;// 混合捕捉auto func1 [x, y](){//...};// 全部引用捕捉auto func2 [](){//...};// 全部传值捕捉auto func3 [](){//...};// 全部引用捕捉x传值捕捉auto func4 [, x](){//...};return 0;
}lambda表达式的优点是可以使代码更加简洁紧凑并且可以避免定义不必要的函数对象。Lambda表达式的缺点是可能会降低代码的可读性和可维护性。
6. 声明
6.1 auto
auto是C11引入的一个关键字用于在声明变量时自动推导变量的类型。auto的使用可以让编译器在编译期间自动推算出变量的类型这样就可以更加方便的编写代码了。auto还可以用于定义函数返回值类型但此时auto仍然使用的是模板实参推断的机制因此返回类型为auto的函数如果返回一个初始化列表则会出错。
6.2 decltype
在C11中decltype 是一种用于推导表达式类型的关键字。decltype 可以用于推导变量、函数返回值、表达式等的类型。decltype 的语法格式如下
decltype(expression)其中expression 是要推导类型的表达式。
以下是一个使用 decltype 的例子
#include iostreamint main()
{int i 42;decltype(i) j i 1;std::cout i i , j j std::endl;return 0;
}以上代码中使用了 decltype 推导了变量 j 的类型。
decltype 的优点是可以在编译期间推导出表达式的类型从而提高程序的效率。decltype 的缺点是可能会降低代码的可读性和可维护性。
6.3 nullptr
C11中nullptr是一个用于表示空指针的关键字它可以替代C03中的0或NULL。nullptr的类型是std::nullptr_t它可以隐式转换为任意类型的指针或成员指针但不能转换为整数类型或布尔类型。nullptr的优点是可以避免一些类型推导的歧义例如在函数重载或模板参数推导时。nullptr的缺点是可能会与一些旧代码不兼容例如使用NULL作为整数常量的代码。
在C中NULL被定义成字面量0这样就可能回带来一些问题因为0既能指针常量又能表示整形常量。所以出于清晰和安全的角度考虑C11中新增了nullptr用于表示空指针。
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif7. 可变参数模版
在C11中可变参数模板是一种用于定义可变数量参数的模板。它允许模板函数或类接受任意数量的参数包括类型、非类型和模板参数。可变参数模板的语法格式如下
templatetypename... Args
void foo(Args... args)
{// 函数体
}其中Args 是一个模板参数包可以接受任意数量的模板参数。在函数体中可以使用 args… 来展开参数包以便对每个参数进行操作。
可变参数模版中有一点需要注意在使用sizeof()求可变参数的个数时应该这样书写:sizeof…(args)//错误格式sizeof(args…)如下所示
template class ...Args
void ShowList(Args... args)
{cout sizeof...(args) endl; //求可变参数的个数
}
int main()
{ShowList(1);ShowList(1, 2.2);ShowList(1, 2.2, hello);return 0;
}如何解析可变参数包这里使用递归来解决。以下是一个使用可变参数模板的例子
void ShowList() //函数重载,当参数个数为0时没有该函数就会找不到匹配的函数
{cout endl;
}
template class T, class ...Args
void ShowList(const T val, Args... args) //每次从参数包中解析一个
{cout val ;ShowList(args...);
}
int main()
{ShowList(1);ShowList(1, 2.2);ShowList(1, 2.2, three);return 0;
}可变参数模板的优点是可以使代码更加灵活和通用可以接受任意数量和类型的参数。可变参数模板的缺点是可能会降低代码的可读性和可维护性。