C++Primer_学习笔记(七)

2019年4月24日

 

4.14.3 显示转换

    显示转换也被称为强制类型转换(cast),报货一下命名的强制类型转换操作符:static_cast、dynamic_cast、const_cast和reinterpret_cast。虽然有时候确实需要强制类型转换,但是它们也是程序错误的的源泉。通过使用它们,程序员关闭了C++语言的类型检查设施。在了解怎样把一个值从一中类型强制类型转换成另一种类型之前,我们先来看下何时需要这么做。

    任何非const数据类型的指针都可以被赋给void* 类型的指针。void*型指针被用于“对象的确切类型未知”或者“在特定环境下对象的类型会发生变化”的情况下。还有时候void*型的指针被称为泛型(geneiric)指针,因为它们可以指向任意数据类型的指针。例如:

    int ival;

    int *pi =0;

    char *pc = 0 ;

    void *pv;

    pv = pi;

    pv = pc;


    const int *pci = &ival;

    pv = pci ;// 错误pv 不是一个 const void *.

    const void *pcv = pci;//ok

    但是,void*型指针不能直接被解除引用,因为没有类型信息来可用来指导编译器怎样解释底层的位模式。相反,void*的指针必须先被转换成某种特定类型的指针。但是,在c++代码中,不从在void*型指针到特殊类型的指针之间的自动转换。

    执行限时强制转换的第二个原因是希望改变通常的标准转换。例如,下列复合赋值,首先将ival提升成double型,然后再把它加到dval上,最后把结果截取成int型来执行赋值:   

 double dval;

    int ival;

   

    ival += dval;

    我们通过显示地将dval强制转换成int型,笑出了把ival从int型到double型不必要提升:

 

   ival += static_cast<int>(dval);

进行显示强制转换的第三个原因是要避免出现多种转换可能的歧义情况 。

    显式转换符号的一股形式如下:

   cast-name<type>(expression);

注:这里的cast_name是static_cast、const_cast、dynamic_cast和reinterpret_cast之一。const_cast,正如其名字所暗示的,将转换掉表达式的常量性(以及volatile对象的volatile性。)例如:   

 extern char* string_copy(char*);

    const char *pc_str;



    char* pc = string_copy(const_cast<char *>(pc_cast));

    试图用其他第三种形式来转换掉常量性会引起编译错误。类似地,用const_cast来执行一般的类型转换,也会引起编译错误。

    编译器隐式执行的任何类型转换都可以用static_cast显示完成:

    double d = 97.0;

    char ch = static_cast<char>(d);

     无论何时,当我们面对令人费解的运行时刻程序行为时,可能的罪魁祸首首先会会是具有功能障碍的指针。一种原因就是无效的显示强制转换,因此,用reinterpret_cast操作符来执行并标识出所有的显式指针强制转换是很有用的。

(指针错误的第二个原因是它指向的内存变成了无效的。这可能会发生在“我们偶尔删除了一个仍然在被使用的指针”,或者“返回了一个局部对象的地址”时)

    dynamic_cast支持在运行时刻识别由指针或引用指向的类对象。对dynamic_cast的讨论在19.1节介绍运行时刻类型识别时再进行。

 

4.14.4旧式强制类型转换

    前面给出的强制类型转换符号语法,有时被称为新式强制转换符号,它是由标准c++引入的。在它之前,显式强制转换

由非常通用的强制转换语法(现在被称为旧式强制类型转换符号)来实现。虽然标准c++仍然支持旧式强制转换符号,但是我们建议,只有当我们为C语言或标准c++之前的编译器编写代码时才使用这种语法。

    旧式强制类型可以用来代替标准c++中的static_cast、cons_cast或reinterpret_cast。在标准c++之前,我们只能使用旧式强制转换。如果我们希望自己的代码在C++和C语言中都能够编译的话,那么只能使用C语言的强制转换符号。

    对旧式强制类型转换符号的支持是为了对“在标准C++之前写的程序”保持向后兼容性,以及提供与C语言兼容的符号。

 

4.15栈类实例

    栈是计算机科学的一个基本数据抽象,它允许以后进先出(LIFO)的顺序嵌入和获取其中的值。栈的两个基本操作是:向栈中压入(push)一个新值,以及弹出(pop)或获取最后压入的那个值。其他一些操作包括:查询栈是否满full()
或空empty(),以及判断栈的长度size()-即包含多少个元素。

 

5语句

    程序最小的独立单元是语句(statement)。在自然语言中,类似的结构是句子。与句子由句号结束一样,语句一般由分号结束。

5.1简单语句和复合语句

    程序中语句最简单的是形式是空语句,形式如下(仅一个分号):

        ;

    空语句被用在“程序的语法上要求一条语句,而逻辑上却不需要”的时候。

    条件和循环语句在语法上只允许执行一条指定的相关语句。然而在的实践中这是远远不够的。在逻辑上,程序经常需要执行两条或多条语句构成的序列。再这样的情况下,我们用一个复合语句(compound)来代替单个语句。

    例如:   

if(ival0 > ival1)

    {
       int temp = ival0;

       ival0 = ival1;

       ival1 = temp;

}

复合语句是一对花括号括起来的语句序列。复合语句被视为一个独立的单元,它可以出现在程序中任何单个语句可以出现的地方。复合语句不需要用分号作为结束,这是一种附加语法上的便利。

空间复合语句与空语句等价,它为空语句提供了一种替代语法,例如:

while( *string += *inBuf++)

{   }//等价空语句

    包含一条或多条声明的复合语句,在前面的例子中,也称为块(block)或语句块(statement block)。块引入了程序中局部域,在块中声明的标识符,如前面例子中的temp,只在该块中的可见。块、域以及对象的生命周期之后会讨论。

5.2声明语句

    在c++中,对象的定义,如:

   int ival;

    被视为c++语言的一条语句[称作声明语句(declaration statement),尽管在这种情况下称为定义(definition)语句更准确],一般它可以被放在程序中任何允许语句出现的地方。

    对于类对象的定义来说,由于类对象与构造函数和析构函数相关联,所以声明的局部性就变成了必须的了。当把这些对象放在函数或语句块的开始时,发生下面两件事情:

  1. 在做函数或语句块中的任何事情之前,所有类对象的构造函数均被调用。声明的局部性使我们能够把初始化的开销分摊到函数或语句块中。
  2. 或许更重要的是,通常情况下,在函数或语句块内部的所有程序语句都被执行之前,该函数或者语句块就结束了。例如,前面的程序显示了两个非正常终止点:获取文件名失败和打开用户指定的文件失败。在成功地经过这些终止点之前定义类对象会导致执行不必要的构造函数-析构函数对。如果给出足够多的类对象或者需要大量计算的构造函数和析构函数,这将对程序的运行效率产生不必要的影响。虽然结果仍然是正确的,但是有时候性能可能变得不可接受。(专业的C程序员习惯把对象定义放在函数或语句块开始的地方。有时候他们会发现自己的c++程序比等价的C程序性能低得多,这就是原因所在。)

一条声明语句可以由一个或多个对象定义构成。例如,在我们的程序中,在同一条声明语句中定义了两个向量迭代器:

vector<string>::iterator iter = text.begin(),iend = text.end();

它与下面一对声明是等价的:

vector<string>::iterator iter = text.begin();

vector<string>::iterator  iend = text.end();

虽然说,选择哪一种声明方案是个人喜好问题,但是,当我们把对象、指针以及引用混合在一起时,在一条声明语句中放置多个对象定义更容易出错。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值