c++11新特性

embedded/2024/10/15 3:13:13/

1. auto

        自动推导变量类型,简化代码书写。

#include <iostream>
#include <type_traits>#if defined(__linux__) || defined(__linux)
#include <cxxabi.h>
#define TYPE_NAME(var) abi::__cxa_demangle(typeid(var).name(), 0, 0, 0)
#else
#define TYPE_NAME(var) typeid(var).name()
#endifvoid Test() {char a = 'A';auto aa = a;std::cout << "a,aa type: " << TYPE_NAME(a) << ", " << TYPE_NAME(aa) << std::endl;short b = 1;auto bb = b;std::cout << "b,bb type: " << TYPE_NAME(b) << ", " << TYPE_NAME(bb) << std::endl;int c = 1;auto cc = c;std::cout << "c,cc type: " << TYPE_NAME(c) << ", " << TYPE_NAME(cc) << std::endl;float d = 1.0f;auto dd = d;std::cout << "d,dd type: " << TYPE_NAME(d) << ", " << TYPE_NAME(dd) << std::endl;double e = 1.0;auto ee = e;std::cout << "e,ee type: " << TYPE_NAME(e) << ", " << TYPE_NAME(ee) << std::endl;long f = 1;auto ff = f;std::cout << "f,ff type: " << TYPE_NAME(f) << ", " << TYPE_NAME(ff) << std::endl;const long g = 1;auto gg = g;std::cout << "g,gg type: " << TYPE_NAME(g) << ", " << TYPE_NAME(gg) << std::endl;char h[10] = {0};auto hh = h;std::cout << "h,hh type: " << TYPE_NAME(h) << ", " << TYPE_NAME(hh) << std::endl;int *i = nullptr;auto ii = i;std::cout << "i,ii type: " << TYPE_NAME(i) << ", " << TYPE_NAME(ii) << std::endl;const int *j = nullptr;auto jj = j;std::cout << "j,jj type: " << TYPE_NAME(j) << ", " << TYPE_NAME(jj) << std::endl;const int *const k = nullptr;auto kk = k;std::cout << "k,kk type: " << TYPE_NAME(k) << ", " << TYPE_NAME(kk) << std::endl;int &l = c;auto ll = l;std::cout << "l,ll type: " << TYPE_NAME(l) << ", " << TYPE_NAME(ll) << std::endl;const int &m = c;auto mm = m;std::cout << "m,mm type: " << TYPE_NAME(m) << ", " << TYPE_NAME(mm) << std::endl;int &&n = 1;auto nn = n;std::cout << "n,nn type: " << TYPE_NAME(n) << ", " << TYPE_NAME(nn) << std::endl;const int &&o = 1;auto oo = o;std::cout << "o,oo type: " << TYPE_NAME(o) << ", " << TYPE_NAME(oo) << std::endl;const int *&p = j;auto pp = p;std::cout << "p,pp type: " << TYPE_NAME(p) << ", " << TYPE_NAME(pp) << std::endl;const int *q = j;const auto &qq = j;std::cout << "q,qq type: " << TYPE_NAME(q) << ", " << TYPE_NAME(qq) << std::endl;
}int main(int argc, char *argv[]) {std::cout << "Hello World" << std::endl;Test();return 0;
}

执行结果:

Hello World
a,aa type: char, char
b,bb type: short, short
c,cc type: int, int
d,dd type: float, float
e,ee type: double, double
f,ff type: long, long
g,gg type: long, long
h,hh type: char [10], char*
i,ii type: int*, int*
j,jj type: int const*, int const*
k,kk type: int const*, int const*
l,ll type: int, int
m,mm type: int, int
n,nn type: int, int
o,oo type: int, int
p,pp type: int const*, int const*
q,qq type: int const*, int const*

2. decltype

        推导实体的声明类型,或表达式的类型和值类别。

#include <iostream>
#include <type_traits>#if defined(__linux__) || defined(__linux)
#include <cxxabi.h>
#define TYPE_NAME(var) abi::__cxa_demangle(typeid(var).name(), 0, 0, 0)
#else
#define TYPE_NAME(var) typeid(var).name()
#endifstruct A {double x;
};const int &GetRef(const int *p) { return *p; }
auto Add(int a, int b) -> decltype(a + b) { return a + b; }void Test() {int a = 33;decltype(a) b = a * 2;std::cout << "a,b type: " << TYPE_NAME(a) << ", " << TYPE_NAME(b)<< std::endl;const A *c = nullptr;decltype(c->x) d;decltype((c->x)) e = d;std::cout << "d,e type: " << TYPE_NAME(d) << ", " << TYPE_NAME(e)<< std::endl;const int *const f = &a;decltype(f) g = &b;std::cout << "f,g type: " << TYPE_NAME(f) << ", " << TYPE_NAME(g)<< std::endl;int &aref = a;decltype(aref) h = a;decltype(Add(10, 20)) i;std::cout << "h,i type: " << TYPE_NAME(f) << ", " << TYPE_NAME(g)<< std::endl;
}

执行结果

a,b type: int, int
d,e type: double, double
f,g type: int const*, int const*
h,i type: int const*, int const*

3. default & delete

        由开发者控制函数由编译器创建(default)或禁止创建(delete),用于构造、析构系列函数。

class A {A() = delete;A(const A &) = default;A(A &&) = default;A &operator=(const A &) = default;A &operator=(A &&) = delete;~A() = default;
};

4. final & override

        final 用于指定某个虚函数不能在派生类中被重写,或者某个类不能被派生;override指定一个虚函数重写另一个虚函数,用于派生类虚函数重写了基类某个虚函数,如果没有重写编译报错。

#include <iostream>
#include <string>struct A final { virtual void Print(const std::string &str) { std::cout << str << std::endl; }
}
#include <iostream>
#include <string>struct A {A() = default;virtual void Print(const std::string &str) final {std::cout << "A " << str << std::endl;}virtual void Print2(const std::string &str) {std::cout << "A2 " << str << std::endl;}
};struct B : public A {B() : A() {}virtual void Print2(const std::string &str) override {std::cout << "B2 " << str << std::endl;}
};void Test() {A a;a.Print("a invoke");a.Print2("a invoke 2");B b;b.Print("B invoke");b.Print2("b invoke 2");A *c = new B();c->Print("c invoke");c->Print2("c invoke 2");delete c;
}int main(int argc, char *argv[]) {Test();return 0;
}

5. 尾随返回类型

        当返回类型取决于实参名时或当返回类型复杂时,尾随返回类型很有用。

#include <iostream>template <class T, class U> auto Add(T t, U u) -> decltype(t + u) {return t + u;
}void Test() {int a = 10;double b = 20;std::cout << "a + b = " << Add(a, b) << std::endl;
}int main(int argc, char *argv[]) {Test();return 0;
}

执行结果

a + b = 30

6. 右值引用

  1. 左值:可修改的变量或表达式。
  2. 右值:常量、表达式等不能出现在等式左边。
  3. 左值引用(&):左值变量的引用别名,传统的引用都是左值。
  4. 右值引用(&&):右值变量的引用别名,一般只能引用右值,可使用std::move转化为右值,实现移动语义。
  5. 完美转发:不修改传递的变量或表达式语义,进行完整的语义传递,即左值参数传递后还是左值,左右参数传递后还是右值。
#include <iostream>void Test() {int a = 10;   // a 左值, 10右值int &aa = a;  // aa 左值引用int &&aaa = std::move(a); // aaa 右值引用,此时 a 在后边作用域内无意义int b = 0;int &bb = b;int &&bbb = std::move(b);const int c = 20;const int &cc = c;// int &&ccc = std::move(c);const int &d = bbb; // const 修饰的引用可以是左值、也可以是右值
}int main(int argc, char *argv[]) {Test();return 0;
}
void Func(const int&& x) { cout << "const 右值引用" << endl; }template<typename T>
void Test(T&& t)
{// Func(t); //没有使用forward保持其右值的属性,退化为左值Func(std::forward<T>(t));  // 使用 std::forward 实现完美转发
}

7. 移动构造

        移动构造函数是一种构造函数,可以提供一个相同类类型实参调用,并复制该实参的内容,有可能会修改实参。

struct A {A() = default;~A() = default;A(const A &) { std::cout << "A(const A&)" << std::endl; }A(A &&) { std::cout << "A(A&&)" << std::endl; }A(const A &&) { std::cout << "const A(A&&)" << std::endl; }A(const volatile A &&) { std::cout << "const volatile A(A&&)" << std::endl; }A(A &&, int num) { std::cout << "A(A&&), num = " << num << std::endl; }int x = 10;
};void Test() {A a;A b = a;A bb = std::move(a);const A c; // 只读变量A d = std::move(c);const volatile A e; // 只读变量A f = std::move(e);a.x = 20;std::cout << "a.x = " << a.x << std::endl;b.x = 30;std::cout << "b.x = " << b.x << std::endl;bb.x = 40;std::cout << "bb.x = " << bb.x << std::endl;d.x = 60;std::cout << "d.x = " << d.x << std::endl;f.x = 80;std::cout << "f.x = " << f.x << std::endl;
}int main(int argc, char *argv[]) {Test();return 0;
}

执行结果

A(const A&)
A(A&&)
const A(A&&)
const volatile A(A&&)
a.x = 20
b.x = 30
bb.x = 40
d.x = 60
f.x = 80

8. 移动赋值运算符

        移动赋值运算符是名字是 operator= 的非模板非静态成员函数,可以提供一个相同类类型实参调用,并复制该实参的内容,有可能会修改实参。

#include <iostream>struct A {A() = default;~A() = default;A &operator=(const A &) {std::cout << "A &operator=(const A &)" << std::endl;}A &operator=(A &&) { std::cout << "A &operator=(A &&)" << std::endl; }A &operator=(const A &&) {std::cout << "A &operator=(const A &&)" << std::endl;}int x = 10;
};void Test() {A a;a.x = 20;A b;b = a;// const A c = a;  // 复制构造函数A d;d = std::move(a);// const A e = std::move(a);  // 复制构造函数a.x = 20;std::cout << "a.x = " << a.x << std::endl;b.x = 30;std::cout << "b.x = " << b.x << std::endl;d.x = 60;std::cout << "d.x = " << d.x << std::endl;
}int main(int argc, char *argv[]) {Test();return 0;
}

执行结果

A &operator=(const A &)
A &operator=(A &&)
a.x = 20
b.x = 30
d.x = 60

9. 作用域枚举

        枚举 是一种独立的类型,它的值被限制在一个取值范围内(细节见下文),它可以包含数个明确命名的常量(“枚举项”)。各常量的值是某个整数类型(称为该枚举的底层类型)的值。枚举的大小、值表示和对齐要求与它的底层类型相同。而且枚举的每个值都与该枚举的底层类型的对应值有着相同的表示。

#include <iostream>enum EnumColor { kRed = 0, kGreen, kBlue };
enum class EnumClassColor { kRed = 3, kGreen, kBlue };
enum class EnumClassColorType : int { kRed = 6, kGreen, kBlue };void Test() {std::cout << "EnumColor: " << EnumColor::kRed << ", " << kGreen << ", "<< kBlue << std::endl;std::cout << "EnumClassColor: " << int(EnumClassColor::kRed) << ", "<< int(EnumClassColor::kGreen) << ", " << int(EnumClassColor::kBlue)<< std::endl;std::cout << "EnumClassColorType: " << int(EnumClassColorType::kRed) << ", "<< int(EnumClassColorType::kGreen) << ", "<< int(EnumClassColorType::kBlue) << std::endl;
}int main(int argc, char *argv[]) {Test();return 0;
}

执行结果

EnumColor: 0, 1, 2
EnumClassColor: 3, 4, 5
EnumClassColorType: 6, 7, 8

10. constexpr

        指定变量或函数的值可以在常量表达式中出现,必须初始化。字面类型是constexpr类型拥有的类型,且能通过constexpr函数构造、操作及返回它们。

#include <iostream>constexpr int Ret() { return 0; }
constexpr bool b2 = noexcept(Ret()); // true,f() 是常量表达式constexpr int Add() { return 10 + 20; }static constexpr char *COLOR[3]{"kRed", "kGreen", "kBlue"};void Test() {constexpr int NUM = 10;static constexpr int NUM2 = 20;static constexpr int const NUM3 = 30;static constexpr int const &NUM4 = 40;constexpr int ARR[2] = {0, 1};std::cout << "Add: " << Add() << std::endl; // 30
}int main(int argc, char *argv[]) {Test();return 0;
}

11. 列表初始化

         从花括号包围的初始化器列表列表初始化对象,默认std::initializer_list类为构造参数。C++98中,标准允许使用花括号{}对数组元素进行统一的列表初始值设定。C++98对于自定义类型,无法使用列表初始化。

#include <iostream>
#include <map>
#include <vector>struct A {A(int a, int b) {}private:int m_a;int m_b;
};void Test() {int arr1[5]{1, 2, 3, 4, 5};int arr2[]{1, 2, 3, 4, 5};int *arr3 = new int[5]{1, 2, 3, 4, 5}; // 动态数组,在C++98中不支持std::vector<int> v{1, 2, 3, 4, 5};std::map<int, int> m{{1, 1}, {2, 2}, {3, 3}, {4, 4}};delete[] arr3;int a = 1 + 3;int b = {1 + 3};int c{1 + 3};A d = {4, 5};A e{6, 7};
}int main(int argc, char *argv[]) {Test();return 0;
}

12. 委托构造 & 继承构造

        如果类自身的名字在初始化器列表中作为类或标识符 出现,那么该列表只能由这一个成员初始化器组成;这种构造函数被称为委托构造函数,而构造函数列表的仅有成员所选择的构造函数是目标构造函数。此时首先由重载决议选择目标构造函数并予以执行,然后控制返回到委托构造函数并执行其函数体。委托构造函数不能递归。

        c++语言当中的继承关系,只有虚函数可以被继承,而构造函数不可以是虚函数,所以构造函数不能被继承,但是我们可以通过某种手段,达到继承效果

class A
{
public: A(char x, int y) {}A(int y) : A('a', y) {} // A(int) 委托到 A(char, int)
};
#include <iostream>struct A {A(int a, int b, int c) {}
};struct B : A {using A::A;int m_a;
};void Test() {A a(1, 2, 3);B b(1, 2, 3); // 调用 A 构造函数, 未初始化 m_a// B c;
}int main(int argc, char *argv[]) {Test();return 0;
}

13. nullptr

        关键词 nullptr 代表指针字面量。它是std::nullptr_t类型的纯右值。存在从 nullptr 到任何指针类型及任何成员指针类型的隐式转换。同样的转换对于任何空指针常量也存在,空指针常量包括std::nullptr_t的值,以及宏 NULL。

#include <type_traits>
#include <iostream>#if defined(__linux__) || defined(__linux)
#include <cxxabi.h>
#define TYPE_NAME(var) abi::__cxa_demangle(typeid(var).name(), 0, 0, 0)
#else
#define TYPE_NAME(var) typeid(var).name()
#endifvoid Test() {std::nullptr_t ptr = nullptr;std::cout << "ptr type: " << TYPE_NAME(ptr) << std::endl;int *ptr2 = nullptr;std::cout << "ptr2 type: " << TYPE_NAME(ptr2) << std::endl;
}int main(int argc, char *argv[]) {Test();return 0;
}

执行输出

ptr type: decltype(nullptr)
ptr2 type: int*

14. long long类型

        long long - 目标类型将有至少 64 位的宽度。具体与平台架构实现相关,long类型规定大于等于32位宽度。

15. char16_t & char32_t

        char16_t - UTF-16 字符表示的类型,要求大到足以表示任何 UTF-16 编码单元(16 位)。它与std::uint_least16_t具有相同的大小、符号性和对齐,但它是独立的类型。

        char32_t - UTF-32 字符表示的类型,要求大到足以表示任何 UTF-32 编码单元(32 位)。它与std::uint_least32_t具有相同的大小、符号性和对齐,但它是独立的类型。

16. 类型别名

        类型别名是指代先前定义的类型的名字(类似 typedef)。别名模版是指代一族类型的名字。

#include <iostream>
#include <string>
#include <type_traits>
#include <typeinfo>// 类型别名,等同于 typedef std::ios_base::fmtflags flags;
using flags = std::ios_base::fmtflags;
flags fl = std::ios_base::dec;// 类型别名,等同于 typedef void (*func)(int, int);
using func = void (*)(int, int);
void example(int, int) {}
func f = example;// 别名模板
template <class T> using ptr = T *;
ptr<int> x;// 用于隐藏模板形参的别名模版
template <class CharT>
using mystring = std::basic_string<CharT, std::char_traits<CharT>>;
mystring<char> str;// 别名模板可引入成员 typedef 名
template <typename T> struct Container { using value_type = T; };// 可用于泛型编程
template <typename ContainerType> void info(const ContainerType &c) {typename ContainerType::value_type T;std::cout << "ContainerType 是 `" << TYPE_NAME(typeid(decltype(c)).name())<< "`\n""value_type 是 `"<< typeid(T).name() << "`\n";
}// 用于简化 std::enable_if 语法的类型别名
template <typename T> using Invoke = typename T::type;template <typename Condition>
using EnableIf = Invoke<std::enable_if<Condition::value>>;template <typename T, typename = EnableIf<std::is_polymorphic<T>>>
int fpoly_only(T) {return 1;
}struct S {virtual ~S() {}
};int main() {Container<int> c;info(c); // Container::value_type 将在此函数中是 int//  fpoly_only(c); // 错误:被 enable_if 禁止S s;fpoly_only(s); // OK:被 enable_if 允许
}

执行结果

ContainerType 是 `char const*`
value_type 是 `i`

17. 可变参模板

        模板形参包是接受零个或更多个模板实参(非类型、类型或模板)的模板形参。函数形参包是接受零个或更多个函数实参的函数形参。至少有一个形参包的模板被称作变参模板

#include <iostream>void tprintf(const char* format) // 基础函数
{std::cout << format;
}template<typename T, typename... Targs>
void tprintf(const char* format, T value, Targs... Fargs) // 递归变参函数
{for (; *format != '\0'; format++){if ( *format == '%' ){std::cout << value;tprintf(format + 1, Fargs...); // 递归调用return;}std::cout << *format;}
}int main()
{tprintf("% world% %\n", "Hello", '!', 123);
}

执行结果

Hello world! 123


http://www.ppmy.cn/embedded/123963.html

相关文章

C#单元测试(一):用 NUnit 和 .NET Core 进行单元测试

本教程通过一步步构建示例解决方案&#xff0c;为您提供一个互动体验&#xff0c;帮助您学习单元测试的概念。如果您更愿意使用预先构建的解决方案来学习本教程&#xff0c;可以在开始之前查看或下载示例代码。下载说明请参阅“示例与教程”部分。 创建源项目 打开一个终端窗…

毕业设计 大数据电影数据分析与可视化系统

文章目录 0 简介1 课题背景2 效果实现3 爬虫及实现4 Flask框架5 Ajax技术6 Echarts7 最后 0 简介 今天学长向大家介绍一个机器视觉的毕设项目 &#x1f6a9;基于大数据的电影数据分析与可视化系统 项目运行效果(视频)&#xff1a; 毕业设计 大数据电影评论情感分析 &#x1…

Vue 中的路由:构建强大的单页应用导航

文章目录 一、什么是 Vue Router&#xff1f;二、基本使用方法三、路由导航四、路由参数五、命名路由六、嵌套路由七、路由守卫八、总结 在 Vue 开发中&#xff0c;路由&#xff08;Vue Router&#xff09;是一个至关重要的工具&#xff0c;它为单页应用&#xff08;SPA&#x…

第 21 章 一条记录的多幅面孔——事务的隔离级别与 MVCC

21.1 事前准备 CREATE TABLE hero ( number INT, NAME VARCHAR ( 100 ), country VARCHAR ( 100 ), PRIMARY KEY ( number ) ) ENGINE INNODB CHARSET utf8;INSERT INTO hero VALUES ( 1, 刘备, 蜀 );21.2 事务隔离级别 在保证事务隔离性的前提下&#xff0c;使用不同的隔…

软考面向对象 ----(封装,继承,多态,面向对象设计原则)

文章目录 一、面向过程和面向对象二、类三、对象&#xff0c;消息四、重载五、封装六、继承&#xff08;extends&#xff09;七、多态八、静态&#xff0c;动态绑定九、面向对象设计原则十、面向对象分析&#xff0c;设计&#xff0c;测试&#xff0c; 一、面向过程和面向对象 …

C++类和对象下详细指南

C类和对象下详细指南 1. 初始化列表与构造函数 1.1 初始化列表概述 初始化列表在C中用于初始化对象的成员变量&#xff0c;特别是当你需要在对象构造时就明确成员变量的值时。通过初始化列表&#xff0c;成员变量的初始化可以在进入构造函数体之前完成。这不仅可以提升性能&…

SpringMVC源码-AbstractHandlerMethodMapping处理器映射器将@Controller修饰类方法存储到处理器映射器

SpringMVC九大内置组件之HandlerMapping处理器映射器-AbstractHandlerMethodMapping类以及子类RequestMappingHandlerMapping如何将Controller修饰的注解类以及类下被注解RequestMapping修饰的方法存储到处理器映射器中。 从RequestMappingHandlerMapping寻找: AbstractHandle…

从DBA是“擦车的”谈起

前段时间有网友在群里讨论&#xff0c;把数据库代码工作者比做是造车的&#xff0c;业务应用开发人员是开车的&#xff0c;而数据库管理员(DBA)则是擦车的。有网友评论这句话&#xff0c;“伤害性不大&#xff0c;侮辱性极强”。说实在的&#xff0c;个人觉得这个说法虽然有些偏…