(嵌入式八股)第3章 C++11(一)
3.1 NULL 和 nullptr 的区别
NULL
和 nullptr
都用于表示空指针,但它们在类型、使用场景和安全性上存在一些区别。
类型区别:
NULL
是宏定义,通常定义为0
,它是一个整数类型,表示空指针。nullptr
是 C++11 引入的关键字,表示一个专门用于指针类型的空值。
安全性区别:
NULL
作为宏定义,它可能被错误地解释为整型0
,因此在某些情况下可能会导致二义性问题。nullptr
是一个专门的空指针类型,类型为std::nullptr_t
,因此避免了NULL
所引起的二义性。
上下文匹配:
NULL
可以在整型上下文中使用(例如传递给整型函数),但nullptr
只能用于指针上下文。
例子(NULL二义性报错):
例子(nullptr消除二义性):
nullptr
来消除二义性。nullptr
是 C++11 引入的,表示空指针,并且它具有明确的类型 std::nullptr_t
,避免了与整型 0
的混淆。func()
时,使用 nullptr
替换 NULL
。总结
- NULL 是一个整数值(通常为
0
),在 C++ 中可能会导致一些二义性问题,特别是在函数重载和模板编程中。 - nullptr 是 C++11 引入的一个专门用于表示空指针的关键字,它的类型是
std::nullptr_t
,避免了NULL
所引起的类型问题。 nullptr
在函数重载等场景中更安全、更清晰,因为它不容易被误解释为整数类型。
3.2 auto 类型推导
auto
是一个非常有用的关键字,用于自动推导变量的类型。通过 auto
,编译器会根据变量初始化时的表达式类型来推导变量的类型。这使得编程更加简洁,尤其是当类型非常复杂或冗长时。
基本语法
variable_name
:变量名expression
:初始化表达式,编译器根据此表达式推导出变量的类型auto 的优点
- 简化代码:对于复杂的类型声明,
auto
可以避免重复写出复杂的类型,增强代码可读性。 - 避免类型错误:通过
auto
,可以减少手动写出类型时发生类型错误的风险,尤其在使用模板和 STL 容器时。 - 适用于所有类型:可以用于推导基本数据类型、指针类型、引用类型,甚至是模板类型。
使用 auto 的示例
示例 1:基本数据类型
变量 a
被自动推导为 int
类型,b
被推导为 double
类型。
示例 2:使用 auto 与指针
变量 ptr
被自动推导为 int*
类型,并指向变量 x
。
示例 3:使用 auto 与引用
变量 ref
被自动推导为 int&
类型,表示 x
的引用。修改 ref
也修改了 x
的值。
示例 4:auto 与容器迭代器
在使用 STL 容器时,auto
是非常有用的,尤其是容器的迭代器类型较为复杂。
使用 auto
让编译器推导出 it
的类型为 vector<int>::iterator
,避免手动写出复杂的类型。
限制与注意事项
auto
必须初始化:编译器根据初始化表达式推导类型,因此必须在声明时进行初始化。- 不能与
const
、volatile
等修饰符混用:如果需要修饰变量为常量引用,应该显式地使用const
。
auto
与 decltype
区别:
auto
根据初始化表达式推导类型。decltype
根据给定表达式的类型来推导变量类型,decltype
不要求初始化。3.3 decltype 类型推导
decltype
是 一个关键字,用于推导表达式的类型。与 auto
不同,decltype
关注的是 表达式的类型,而 auto
根据 初始化值 来推导类型。decltype
可以非常精确地得到一个表达式的类型,并且它不会计算表达式的值。
decltype 简介
decltype
用于根据表达式的类型推导变量类型,且不会实际计算表达式的值。其语法如下:
说明:
expression
是一个表达式,编译器会根据这个表达式来推导出它的类型。variable_name
是变量名,decltype
会推导出该变量的类型。
decltype(x)
会推导出x
的类型,假设x
是int
类型,那么y
的类型也将是int
。typeid(y).name()
会返回一个表示y
类型的名称的字符串,尽管不同的编译器返回的类型名称格式可能不同,但通常会类似于“int”这种形式。在某些编译器中,它可能返回“i”而不是“int”。decltype
与 auto
的区别
decltype 推导规则
普通表达式或变量
- 如果表达式不是左值,
decltype
返回表达式的类型。
函数调用
- 如果表达式是一个函数调用,
decltype
返回该函数的返回值类型。
左值
- 如果表达式是左值(例如变量或数组元素),
decltype
返回表达式的引用类型。
在上述示例中,decltype((x))
会推导出 x
的引用类型(int&
),因为 (x)
是一个左值表达式。
decltype 示例代码
示例 1:基础类型推导
decltype(x)
将推导出x
的类型(int
),因此y
被声明为int
类型。
示例 2:函数返回类型推导
decltype(add(1, 2))
将推导出add
函数的返回值类型(int
),因此result
的类型是int
。
示例 3:左值推导
decltype(x)
返回 int
类型。decltype((x))
返回 int&
类型,因为 (x)
是一个左值。总结
decltype
用于推导表达式的类型,而auto
根据初始化值推导变量的类型。decltype
不会计算表达式的值,仅通过类型推导来获取变量的类型。decltype
可以处理各种复杂的表达式,特别是在模板编程中非常有用。
3.4 override 和 final 关键字
在 C++11 中,override
和 final
是两个非常有用的关键字,它们用于增强代码的可读性和安全性,特别是在处理继承和虚函数时。
override 关键字
override
关键字用于显式地指示派生类中的成员函数是对基类中的虚函数的重写。使用 override
可以提高代码的可读性,并确保派生类的函数正确地覆盖了基类中的虚函数。
作用:
- 明确重写:
override
使得代码更清晰,表明该函数确实是重写了基类的虚函数。 - 编译时检查:使用
override
时,编译器会确保派生类的函数签名(包括返回类型、参数类型等)与基类的虚函数完全匹配。如果签名不匹配,编译器会报错,从而避免因函数签名错误而导致的错误。
Derived
类中的show()
函数使用override
显式标明是重写了基类的show()
函数。- 如果
Derived
类中的show()
函数的签名不匹配基类中的show()
,编译器将报告错误。
错误示例:
final 关键字
final
关键字用于指示一个类或虚函数不能被继承或重写。它有两个主要用途:
- 标记类不能被继承:如果一个类被声明为
final
,则无法在该类的基础上创建派生类。 - 标记虚函数不能被重写:如果一个虚函数被声明为
final
,则派生类不能重写该函数。
final
用于类:
FinalClass
被声明为final
,意味着它不能被任何类继承。- 如果你尝试从
FinalClass
继承(如Derived
类所示),编译器会报错,因为FinalClass
已经被标记为最终类,不能被继承。
final
用于虚函数:
Base
类中的 show()
被声明为 final
,表示该函数不能被派生类重写。Derived
类中重写 show()
函数时,编译器会报错,因为该函数已经被标记为 final
。override 与 final 的组合使用
override
和 final
可以一起使用,用于标记一个函数既是重写基类函数,又是最终版本,不能被进一步重写。通常,final
用于防止继承和重写,override
用于清晰地表示函数的重写。
show()
是一个虚函数,允许派生类重写。final
,因为它需要允许派生类覆盖该函数。show()
使用 override
显式标明它是重写了基类的虚函数。show()
使用 final
标记,表示这个重写版本不能再被进一步重写。Derived
类中的 show()
已被标记为 final
,因此在 AnotherDerived
类中尝试重写 show()
时,编译器会报错,防止对 Derived
中的 show()
进行进一步重写obj.show()
将调用 Derived
类中的 show()
,输出 "Derived class"
。AnotherDerived obj2; obj2.show();
,编译器将报错,因为 AnotherDerived
中无法重写 Derived
类中的 show()
函数。总结
override
用于显式标明派生类中的成员函数是基类虚函数的重写,增强代码的可读性,并让编译器帮助检查函数签名是否匹配。final
用于标记类或虚函数不能被继承或重写,增加代码的安全性,防止不小心的继承或重写。- 两者可以组合使用,确保函数既是重写的又是最终版本,不能被进一步修改。
3.5 Lambda 表达式
Lambda 表达式 是 C++11 引入的一种新特性,允许创建 匿名函数,通常用于 简化代码、提高可读性,并可在 函数内部 定义内联函数,而不需要单独定义函数。
Lambda 表达式的基本语法
Lambda 表达式的基本语法如下:
capture list
(捕获列表):指定 Lambda 表达式可以访问的外部变量。剩余60%内容,订阅专栏后可继续查看/也可单篇购买
作者简介:仅用几个月时间0基础天坑急转嵌入式开发,逆袭成功拿下华为、vivo、小米等15个offer,面试经验100+,收藏20+面经,分享求职历程与学习心得。 专栏内容:这是一份覆盖嵌入式求职过程中99%问题指南,详细讲解了嵌入式开发的学习路径、项目经验分享、简历优化技巧、面试心得及实习经验,从技术面,HR面,AI面,主管面,谈薪一站式服务,助你突破技术瓶颈、打破信息差,争取更多大厂offer。