More extensions to C , Some features of C++11
对于稍微有些C++的同学,大概都知道C++和C的一些主要区别,大的区别就是一个是面向对象,一个是面向过程,这就涉及到对象; 同时,还有命名空间的引入,防止变量名冲突; 还有struct支持成员函数等。 我就继续注释一些更需要注意的一些不同,一些是C++11中的东西。
引用
可以通过引用修改它引的对象,但是不能改变它本身。这么听来,就像是常量指针, 另外,引用也让代码更加自然,不像c里边会出现一堆的&来表示传址调用。
int a
=
1;
int
&r
=a;
int
*
const rr
= a;
// int*const 和 int&是同一个东西,引用只是一个语法糖。
使用引用时,有几点需要记住:
引用定义时必须初始化! 其实看上面的程序例子就知道, const的东西都必须初始化
不要在函数中返回局部变量的引用
函数中是否使用引用的场合
引用,可以当做函数参数传入,这样就可能会修改所引用对象。指针也能达到这样的目的,这样多多少少会造成一些困惑,我们可以依从一些原则:
若形参是内建类型(int double char等),且我们不需要改变实参值,直接传值调用
若形参时内建类型,且我们需要修改它,那就通过指针*调用
若形参类型是类,结构体等,我们不需要改变它的成员变量,采用 const & 调用
若形参类型是类等,需要改变,采用引用&调用
使用引用调用,能够避免构造函数的调用,节省开支。
另外,需要实现链式操作的,返回值选择引用类型,也能避免构造函数的调用。经典例子就是 “cout”
右值引用 (对C++11不是很熟悉,会有一些理解上的错误,请指正)
C++11中多了个右值引用。 主要是因为临时变量(右值)不能很好的同 const& 很好的区分开来,因此C++11多了个右值引用&&。
举例说明下:
int intVa()
{
return
5;
}
int
& a
= intVal();
// 错误! 引用临时变量
int
const
& a
= intVal();
// 正确,引用不变临时变量
int
* a
=
&intVal();
// 错误! intVal()不是左值
我们继续看:
void receive(
int
& value){
++value; cout
<<“L
–value parameter\n”;} // 左值引用版本
void receive(
int
&& value){
++value; cout
<<
“R-value parameter\n”;} // 右值引用版本
void receive(
int
const
& value)
{
++value; cout
<<
“L-value const parameter\n”;}
// ++value不能有,否则编译错误。这算是右值引用和const&的区别。
如此调用:
int main()
{
receive(
18);
// R-value 19
int v
=
5;
int
const
& cri
= v;
receive(cri);
// L-value const
receive(v);
// L-value 6
receive(intVal());
// R-value 6
}
若我们把 void receive(int& value)删除,则receive(v) 返回 L-value const parameter。 函数重载的右值引用版本,仅在匿名变量传入时激发。
另外,右值引用版本函数中,可以对value进行操作,可以看出,右值引用 用于获取 匿名临时变量 的 操纵权,而 int const& 版本的却不行。
注意下:
若引入另外个重载版本 void(int value), 那么将发生错误,因为该例中,匿名变量也可以解析成 int 型,导致重载冲突。
另外,右值引用的进阶应用是 是 移动语义 move semantics 和 完美转发 perfect forwarding 的基础。移动语义我暂时还不懂啥,以后再讲述。
强类型-枚举类
C++中,枚举类型其实就是int,不同枚举类型可以通过static_cast<int> 来进行比较操作;另外,不同枚举类型的内部值不能相同,因为C++中枚举类型的作用范围不被枚举名所限,而是受作用域限制。
C++11中,引入了 enum class ,来解决上述问题。
enum
class CharEnum
:
unsigned
char
// 默认是int,可以通过这个“:”符号改变
{
NOT_OK,
// 默认 0
OK
// 自增1
};
使用时,要加入枚举类名与作用域符,即 CharEnum::OK.
前向声明如下
enum Enum1;
// Illegal: no size available
enum Enum2
:
unsigned
int;
// Legal in C++11: explicitly declared type
enum
class Enum3;
// Legal in C++11: default int type is used
enum
class Enum4
:
char;
// Legal in C++11: explicitly declared type
初始化列表
c语言中,可以用大括号包含一个初始化列表来初始化数组、结构体。C++11把这个概念继续扩展了,引入了
initializer_list<Type> 这个模本类,可以扩展初始化类,同时也能对初始化列表进行个性化操作。 使用前,要包含头文件 <initializer_list> 。同时,可以将初始化列表当做函数形参传入。
void values(initializer_list
<
int
> iniValues)
{
cout
<<
“Initializer list having “
<< iniValues.size()
<<
“values\n”;
for
(
initializer_list
<
int
>
:
:const_iterator begin
= iniValues.begin();
begin
!= iniValues.end();
++begin
)
cout
<<
“Value: “
<<
*begin
<<
‘\n’;
}
这个知识点Mark下,以后继续深入了解,记得在 boost 中好像也有类似的东西。
auto 和 decltype 这个我觉得,最好了
由于C++的声明可能会非常复杂难懂,C++11将曾经的auto关键字改造,使其能够自动解析类型,不错,基于boost的改进。
auto 和 decltype 功能异常强大,不过个人认为,还是要把模板知识搞透了再深入使用这个关键字比较好,基础神马的,最重要的了。
int (*fun())[10], 表示 fun是个函数,返回一个指向int数组[10]的指针。这样不好理解,用上auto后,一切这么自然
auto func() -> int(*)[10];
另外,比如 vector<int>::const_iterator ci = v.begin(); 可以改写成 auto ci = v.begin(); 例子很多,相信auto的使用,会让C++更加受欢迎。
类型定义和 ‘using’ 声明
比如 unsigned long int compute(double, double), 这个函数指针的声明,使用typedef可以变成这样:
typedef unsigned long int(*pfun)(double, double);
但是,我们声明时 pfun f; 时,掩盖了Pfun实际上是一个指针的事实,必须看typedef定义才知道。关于这点,我很诟病,导致我函数指针一直没学好。C++11中将这点进行了升华,采用using 关键字:
using pfun
=
unsigned
long
int(
double,
double);
或者和
auto配合:
using pfun
=
auto (
double,
double)
–
>
unsigned
long
int;
for循环的范围操作
传统C/C++ 的for采用标准的 for(init;cong;next)语句,这对遍历的使用,不那么的便捷,很多语言都提供了范围操作符,在STL的算法库也包含了for_each方法,但是还是不够便捷。C++11中引入了for的范围操作版本:
int array[100];
for (auto &element:array){…}
这里,推荐使用auto,避免思想负担在解析类型上。 同时,element是变量名,表示array中每次遍历的元素。 引用操作符非常重要,若是要修改元素或array是类类型,则用引用; 若是类类型,但不改变,用const&; 普通的内建类型且不改变,可以不用&。
有了这个范围操作,C++算是一大进步呀。
原始字符串
传统C/C++使用””包含字符串,用\来做逃脱而字符。这样,我们会在代码中看到一堆的 \\\\\\ 实在很影响阅读。现在很多语言都支持正则表达式了,而正则中最多也正是\\这样的符号,让C++来使用,my god! 。我觉得C++可能借鉴了python的R字符串,和perl的定界符规则,引出自己的原始字符串,在原始字符串中,不存在逃脱语义。写法如下:
R”(string)” 写法一
R"delimiter(string)delimiter" 写法二
更细致的阐述,打算放在正则表达式时讨论。
新增类型说明符
ob0101: 表示二进制的5
F : 说明是一个浮点型常量 3F
L : 前缀使用说明字符串中字符是wchar_t, 后缀使用说明是一个 long
p :十六进制数*(2^p), 即左移p。
增加对 Unicode 的支持
字符串:
char utf_8[]
= u8
“This is UTF-8 encoded.”;
char16_t utf16[]
= u
“This is UTF-16 encoded.”;
char32_t utf32[]
= U
“This is UTF-32 encoded.”;
对unicode常量,使用\u逃脱,加上一个十六进制量
char utf_8[]
= u8
“\u2018”;
char16_t utf16[]
= u
“\u2018”;
char32_t utf32[]
= U
“\u2018”;
同样,表达式可以使用原始字符串
感慨:C++复杂太多了,多了太多东西了,每个知识点都是一大章的东西,看来,路漫漫呀!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/110125.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】:
Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】:
官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...