C++心得笔记
目录
C++ Primer Plus 第三章 处理数据
3.4.4 类型转换
C++丰富的类型允许根据需求选择不同的类型,这也使计算机的操作更复杂。为处理这种潜在的混乱,C++自动执行很多类型转换:
- 将一种算术类型的值赋给另一种类型的变量时,C++将对值进行转换;
- 表达式时包含不同的类型时,C++将对值进行转换;
- 将参数传递给函数时,C++将对值进行转换。
1、初始化和赋值进行的转换
C++允许将一种类型的值赋给另一种类型的变量。这样做时,值将被转换为接受变量的类型。例如:
long so_long;
short thirty;
so_long = thirty;
进行赋值时,程序将thirty的值(通常是16位)扩展为long值(通常为32位)。扩展后将得到一个新值,这个值被存储在so_long中, 而thirty的内容不变。
将一个值赋给值取值范围更大的类型通常不会导致什么问题。例如,将short值赋给long变量并不会改变这个值,只是占用的字节更多而已。然而,将一个很大的long值(如2111222333)赋给float变量将降低精度。因为float只有6位有效数字,因此这个值将被四舍五入为2.11122E9。因此, 有些转换是安全的,有些则会带来麻烦。
下面的程序演示了一些初始化进行的转换:
#include<iostream>
#include<stdlib.h>
int main()
{
using namespace std;
cout.setf(ios_base::fixed, ios_base::floatfield);
float tree = 3; // int converted to float
int guess(3.9832); // double converted to int
int debt = 7.2E12; // result not defined in C++
cout << "tree = " << tree << endl;
cout << "guess = " << guess << endl;
cout << "debt = " << debt << endl;
system("pause");
return 0;
}
当你将整数变量初始化为浮点值时,有些编译器将提出警告,指出这可能会丢掉数据。
2、以{}方式初始化时进行的转换(C++11)
C++将使用大括号的初始化称为列表初始化(list-initialization),因为这种初始化常用于给复杂的数据类型提供值列表。与上面那个程序所示的初始化方式相比,它对类型转换的要求更严格。具体地说,列表初始化不允许缩窄(narrowing),即变量的类型可能无法表示赋给它的值。
在不同的整型之间转换或将整型转换为浮点型可能被允许,条件是编译器知道目标变量能够正确地存储赋给它的值。例如:
const int code = 66;
int x = 66;
char c1 {31325}; //narring, not allowed
char c2 = {66}; // allowed because char can hold 66
char c3 {code}; // ditto
char c4 = {x}; // not allowed, x is not constant
x = 31325;
char c5 = x; // allowed by this form of initialization
在上述代码中, 初始化c4时, 您知道x的值为66, 但在编译器看来, x是一个变量, 其值可能很大。编译器不会跟踪下述阶段可能发生的情况:从 x被初始化到它被用来初始化c4。
3、表达式中的转换
当同一个表达式中包含两种不同的算术类型时,C++将执行两种自动转换:首先,一些类型在出现时便会自动转换;其次,有些类型在与其他类型同时出现在表达式中时将被转换。
自动转换:在计算表达式时,C++将bool、char、unsigned char、signed char和short值转换为int。具体地说,true被转换为1,false被转换为0。这些转换被称为整型提升(integral promotion)。例如:
short chickens = 20;
short ducks = 35;
short fowl = chickens + ducks;
执行这些语句时,C++程序取得chickens和ducks的值,并将它们转换为int。然后,程序将结果转换为short类型,因为结果将被赋值给一个short变量。(通常int类型选择为计算机最自然的类型)
4、传递参数时的转换
传递参数时的类型转换通常由C++函数原型控制。然而也可以取消原型对参数传递的控制。为保持与传统C语言的大量代码的兼容性,在将参数传递给取消原型对参数传递控制的函数时,C++将float参数提升为double。
5、强制类型转换
C++还允许通过强制类型转换机制显示地进行类型转换。强制类型转换的格式有两种。例如:
(long) thorn // returns a type long conversion of thorn
long (thorn) // returns a type long conversion of thorn
强制类型转换不会修改thorn变量本身,而是创建一个新的、指定类型的值,可以在表达式中使用这个值。第一种格式是来自与C语言,第二种格式是纯粹的C++。
C++还引入了4个强制类型转换运算符,对它们的使用要求更为严格,在这四个运算符中,static_cast<>可用于将值从一种数值类型转换为另一种数值类型。
#include<iostream>
#include<stdlib.h>
int main()
{
using namespace std;
int auks, bats, coots;
auks = 19.99 + 11.99;
bats = (int) 19.99 + (int) 11.99; // old C syntax
coots = int (19.99) + int (11.99); // new C++ syntax
cout << "auks = " << auks << ", bats = " << bats;
cout << ", coots = " << coots << endl;
char ch = 'Z';
cout << "The code for " << ch << " is "; //print as char
cout << int (ch) << endl; // print as int
cout << "Yes, the code is ";
cout << static_cast<int>(ch) << endl; // using static_cast
system("pause");
return 0;
}
3.4.5 C++11中的auto声明
C++11新增了一个工具,让编译器能够根据初始值的类型推断变量的类型。为此,它重新定义了auto的含义。如果使用关键字auto,而不指定变量的类型,编译器将把变量的类型设置程=成与初始值相同:
auto n = 100; // n is int
auto x = 1.5; // x is double
auto y = 1.3e12L; // y is long double
然而,自动推断类型并非为这种简单情况而设计的:事实上,如果将其用于这种简单情形,甚至会出现错误。例如:
auto x = 0.0; // ok, x is double
double y = 0; // ok, 0 automatically converted to 0.0
auto z = 0; // ops, z is int because 0 is int
处理复杂类型,如标准模块库(STL)中的类型时,自动类型推断的优势才能显现出来。例如,对于下述C++98代码:
std::vector<double> sores;
std::vector<double>::iterator pv = scores.begin();
C++11 允许您将其重写为下面这样:
std::vector<double> scores;
auto pv = scores.begin();