C++Primer学习笔记《5》

类型转换在C++的很多代码中存在,更多的是在你看不到的背后执行的隐式类型转换。算术类型之间的转换是为了防止精度的丢失。如果左右操作数不一致且具备转换的条件,右操作数会被转换为左操作数类型。

类型转换发生在哪些地方:在混合表达式中表示范围较小的类型转换为表示范围较大的类型;当算术类型作为条件表达式中,算术类型为被转换为bool类型。

整形提升:整型里面比int小的(char,signedchar,unsigned char,short,unsigned)如果这些类型的范围都能包含于int类型内,那就转换为int类型,如果超出了int的表示范围,那就转换为诶unsigned int类型。如果将bool提升为int,那false转换为0,true转换为1。

有符号和无符号之间的转换:这类转换是依赖于机器中整型的相对大小的,因为表达式中设计到unsigned的转换都是依赖于机器的。当unsigned short包含于int时,就转换为int;否则两个都转换为unsigned int。如果unsigned int包含于long时,那unsigned int转换为long;否则两个都转换为unsigned long。

对于signed和unsigned int之间的转换通常会出乎我们的意料。表达式中的signed会被转换为unsigned int。如果signed恰巧是负数,那就会转换成一个很大的数值,带来副作用。至于为什么一个负数转换为unsigned后会变成很大的数值,这里面涉及到计算机关于有符号整型的存储机制以及运算机制。

大多数情况下数组名会转换为指向数组中第一个元素的同类型指针。

算术类型里面0会转换为bool里的false,其他值会转换为true。但从bool转换到整型的话,false转换为0,true则指定转换为1。

在C++中会自动将枚举类型转换为整型,至于转换为什么类型的整型,这个依赖于机器和枚举成员的最大值,原则是包含最大值的最小类型。如果枚举的成员值均在int范围内,就转换为int;否则就转换为unsigned int,long,unsignedlong等。

当使用非const对象初始化const对象引用时,会被转换为const对象;指针同理。

C++中即可以使用C的类型转换方式,同时也提供了4个专门用于显示类型转换的关键字。他们分别是static_cast,const_cast,dynamic_cast,reinterpret_cast。传统的转换都可以用static_cast来完成;const_cast的唯一用途是用于去除const和volatile属性;dynamic_cast用于运行时的类型识别,主要是用于类继承体系下的各个对象指针之间;reinterpret_cast的实现依赖于机器,主要用于对操作数的位模式在较低层次重新解释,这种转换是建立在使用者非常熟悉类型的表示以及编译器的情况下。

在switch-case语句中,每一个case(label)都是常量表达式。在开关语句中,只能在最后一个case语句或是default语句后面定义变量:防止代码跳过变量的定义与初始化。

Assert(断言机制)是一个预处理宏,只有在没有定义DEBUG宏时候才会检测括号里的表达式真假。一旦开发与测试工作完成,程序已经建立好,并定义了DEBUG宏。在产品代码中,assert遍不会工作。

当程序中产生异常并没有捕捉时会调用标准库函数terminate函数,终止程序。

在C++中使用调用操作符(其实就是一对圆括号,但也是一个操作符,并且还可以重载,函数对象就是基于此的)实现对函数的调用。

在早期的C++版本中,函数可以没有返回类型,其默认是int。但现在C++标准规定必须要返回类型,不过main函数是一个例外。在C++中main函数的标准是返回类型是int,当执行到最后发现没有返回值时,会自动返回0,表示正常结束。

每一次函数调用,都会开辟形参的局部空间,并用实参来初始化。

在函数的形参列表里,int和const int不算重载;但是在函数的后面const可作为重载的标识。

非const引用的形参只能关联完全同类型的引用:

Intincr(int &val)

{    Return ++val;    }

Intmain()

{

Short v1 = 0;

Const int v2 = 1;

Int v3 = incr(v1); 错误,因为v1不是一个整型,不接受可转换类型

V3 = incr(v2);  错误,因为v2是一个const对象

V3 = incr(0);   错误,因为0不是左值

V3 = incr(v1 + v2); 错误,因为v1 + v2是表达式,不是左值

Int v4 = incr(v3);  正确,完全同类型

}

Void printValues(int *);

Void printValues(int []);

Void printValues(int [10]); 这三个函数声明式等价,因为编译器忽略形参的数组长度,只检测实参是否符合同类型指针,不会检测实参的数组长度信息。

通过引用传递数组:

和其他类型一样,数组也有引用,但数组元素内不允许存放引用,所以只有数组引用,没有引用数组。

如果形参是数组的引用,编译器就不会将其转换成指针,而是传递数组本身,这种情况下,编译器会检查实参的数组长度是否和形参规定的一致,不一致就会编译错误。所以传递数组引用可以保证函数内部的代码都是在数组的大小范围内。

Fun(int (&array)[10]);传递数组引用

Fun(int &array[10]);  形式上类似于引用数组,但没有这个名词,属语法错误

在传递多维数组时,编译器忽略第一维长度的检测:

Func(int (*array)[10]);

Fun(int array[][10]);这两句是等价的。

任何处理数组的程序都要确保程序是停留在数组的边界内。以下三种方式可以做到:1在数组内部标识结尾,类似于C风格字符串的空字符;2传递参数时,分别指定数组的第一个元素指针和数组最后一个元素下一个位置的指针,类似于标准库里面的左闭右开原则;3显示的传递数组的长度

含有可变形参的函数:C++中的省略符形参是为了编译使用了varargs的C语言程序。对于C++程序来说,只能将简单的基本类型数据传递给含有省略符形参的函数中。在无法准确列出函数所有实参的类型和数目时,可以使用省略符形参。省略符形参会暂停类型检查。

Void foo( parm_list, … );带有特定数目的形参

Void foo( … );  不带形参

大部分带有省略符形参的函数都利用显示声明的参数中的一些信息,来获取其他可选实参的类型和数目。前一种情况较常用。

如果函数返回类型不是引用,在函数调用出将函数的返回值复制给临时对象。

如果函数返回值是引用,则不用产生复制。但一定要清楚返回的引用是关联哪个对象的,不能返回局部对象的引用或指针。

时间: 2024-10-23 12:36:12

C++Primer学习笔记《5》的相关文章

C++Primer学习笔记《三》

数组名其实就是一个常指针,指向数组元素中第一个的地址,在程序中如果要用指针遍历数组,不能直接用数组名来自增或自减,因为它是常量,一般先把数组名保存一份同类型的指针,然后再用这个指针来自增或是自减来实现遍历. 指针也是可以进行算术加法和减法的,但必须保证原地址和结果地址都是想同一个数组的元素或是指向数组的末端元素的下一个单元(类似end()). 指针的减法操作是有意义的,它表示两个指针的相对位置关系,减法结果是ptrdiff_t类型,和size_t类型一样,是一种机器相关的类型,size_t是无符

C++ Primer学习笔记(三) C++中函数是一种类型!!!

C++中函数是一种类型!C++中函数是一种类型!C++中函数是一种类型! 函数名就是变量!函数名就是变量!函数名就是变量! 重要的事情要说三遍... 接 C++ Primer学习笔记(二) 类的构造函数 与类同名,且无返回类型. 同类的成员函数一样,也可以在类中声明,在类外定义. 格式: 类名(): 成员1(成员1初始化值), 成员2(成员2初始化值) { } 以上,冒号至大括号中间的部分,称为构造函数的初始化列表,用于调用类成员的构造函数来初始化. 没有在初始化列表中显式指定初始化的成员,将会

C++ Primer学习笔记32_面向对象编程(3)--继承(三):多重继承、虚继承与虚基类

C++ Primer学习笔记32_面向对象编程(3)--继承(三):多重继承.虚继承与虚基类 一.多重继承 在C++语言中,一个派生类可以从一个基类派生,称为单继承:也可以从多个基类派生,称为多继承. 多重继承--一个派生类可以有多个基类 class <派生类名> : <继承方式1> <基类名1>,<继承方式2> <基类名2>,... { <派生类新定义成员> }; 可见,多继承与单继承的区别从定义格式上看,主要是多继承的基类多于一个

C++ Primer 学习笔记_35_面向对象编程(6)--虚函数与多态(三):虚函数表指针(vptr)及虚基类表指针(bptr)、C++对象模型

C++ Primer 学习笔记_35_面向对象编程(6)--虚函数与多态(三):虚函数表指针(vptr)及虚基类表指针(bptr).C++对象模型 一.虚函数表指针(vptr)及虚基类表指针(bptr) C++在布局以及存取时间上主要的额外负担是由virtual引起的,包括: virtual function机制:用以支持一个有效率的"执行期绑定": virtual base class:用以实现多次在继承体系中的基类,有一个单一而被共享的实体. 1.虚函数表指针 C++中,有两种数据

C++ Primer 学习笔记_98_特殊工具与技术 --优化内存分配

特殊工具与技术 --优化内存分配 引言: C++的内存分配是一种类型化操作:new为特定类型分配内存,并在新分配的内存中构造该类型的一个对象.new表达式自动运行合适的构造函数来初始化每个动态分配的类类型对象. new基于每个对象分配内存的事实可能会对某些类强加不可接受的运行时开销,这样的类可能需要使用用户级的类类型对象分配能够更快一些.这样的类使用的通用策略是,预先分配用于创建新对象的内存,需要时在预先分配的内存中构造每个新对象. 另外一些类希望按最小尺寸为自己的数据成员分配需要的内存.例如,

C++ Primer 学习笔记_73_面向对象编程 --再谈文本查询示例

面向对象编程 --再谈文本查询示例 引言: 扩展第10.6节的文本查询应用程序,使我们的系统可以支持更复杂的查询. 为了说明问题,将用下面的简单小说来运行查询: Alice Emma has long flowing red hair. Her Daddy says when the wind blows through her hair, it looks almost alive, like a fiery bird in flight. A beautiful fiery bird, he

C++ Primer 学习笔记_19_类与数据抽象(5)_初始化列表(const和引用成员)、拷贝构造函数

C++ Primer 学习笔记_19_类与数据抽象(5)_初始化列表(const和引用成员).拷贝构造函数  从概念上将,可以认为构造函数分为两个阶段执行: 1)初始化阶段: 2)普通的计算阶段.计算阶段由构造函数函数体中的所有语句组成. 一.构造函数初始化列表 推荐在构造函数初始化列表中进行初始化 1.对象成员及其初始化 <span style="font-size:14px;">#include <iostream> using namespace std;

C++ Primer 学习笔记_102_特殊工具与技术 --运行时类型识别[续]

特殊工具与技术 --运行时类型识别[续] 三.RTTI的使用 当比较两个派生类对象的时候,我们希望比较可能特定于派生类的数据成员.如果形参是基类引用,就只能比较基类中出现的成员,我们不能访问在派生类中但不在基类中出现的成员. 因此我们可以使用RTTI,在试图比较不同类型的对象时返回假(false). 我们将定义单个相等操作符.每个类定义一个虚函数 equal,该函数首先将操作数强制转换为正确的类型.如果转换成功,就进行真正的比较:如果转换失败,equal 操作就返回 false. 1.类层次 c

C++ Primer 学习笔记_99_特殊工具与技术 --优化内存分配[续1]

特殊工具与技术 --优化内存分配[续1] 三.operator new函数和operator delete 函数 – 分配但不初始化内存 首先,需要对new和delete表达式怎样工作有更多的理解.当使用new表达式 string *sp = new string("initialized"); 的时候,实际上发生三个步骤: 1)首先,表达式调用名为operator new 的标准库函数,分配足够大的原始的未类型化的内存,以保存指定类型的一个对象; 2)接下来,运行该类型的一个构造函数

C++ Primer 学习笔记_81_模板与泛型编程 --类模板成员[续1]

模板与泛型编程 --类模板成员[续1] 二.非类型形参的模板实参 template <int hi,int wid> class Screen { public: Screen():screen(hi * wid,'#'), cursor(hi * wid),height(hi),width(wid) {} //.. private: std::string screen; std::string::size_type cursor; std::string::size_type height