C++ primer笔记3(7-8)

 

用来区分名字含义的一般上下文就是域(scope)。
C++支持三种形式的域:局部域(local scope)、名字空间域(namespace scope)以及类域(class scope)。
1、局部域是包含在函数定义或者函数块中的程序文本部分。
2、名字空间域是不包含在函数声明函数定义或者类定义内的程序文本部分。
3、每个类定义都引入了一个独立的类域。

名字解析(name resolution)是把表达式中的一个名字与某一个声明相关联的过程,也是给出这个名字的意义的过程。
编译器根据域规则和名字解析规则解释它所读入的程序文本。

局部域内的名字解析是这样进行的:首先查找使用该名字的域,如果找到一个声明则该名字被解析。如果没有找到,则查找包含该域的域。这个过程会一直继续下去,直到找到一个声明或已经查找完整个全局域。如果后一种情况发生 即没有找到该名字的声明,则这个名字的用法将被标记为错误。

关键字extern 为声明但不定义一个对象提供了一种方法。
extern 声明不会引起内存被分配,它可以在同一文件中或同一程序的不同文件中出现多次。

在C++中,有一种机制,通过它可以把函数参数的类型和数目编码在函数名中,该机制叫做类型安全链接(type-safe-linkage)。 类型安全链接可用来帮助捕捉不同文件中函数声明不匹配的情况。

设计头文件需要注意:
1、头文件提供的声明逻辑上应该属于一个组。
编译头文件也需要时间。如果头文件过大,则会增加编译时间。为降低编译时间开销,有些C++提供了预编译头文件支持。

下面给出一个使用预编译头文件的操作步骤, 享受一下预编译头文件给我们带来的编译速度的提升:

1) 添加一个stdafx.h文件(名字随便取, 这里用了VS默认提供的名称), 在这个.h文件里include要使用的头文件(一般是外部的库, 自己写的不常变的头文件也可以加进来)

2) 添加一个stdafx.cpp文件, 并include "stdafx.h"

3)项目属性-->c/c++-->Precompiled设置为Use Precompiled Header, stdafx.h

4)stdafx.cpp属性-->c/c++->Precompiled设置为Create Precompiled Header, stdafx.h

2、头文件不应该含有非Inline函数或对象的定义。
符号常量和Inline函数可以被定义多次。
在程序编译期间,在可能的情况下,符号常量的值会代替该名字的出现。这个替代过程被称为常量折叠(constant folding).

在局部域中的变量声明引入了局部对象(local object)。 有三种局部对象:自动对象(automatic object)、 寄存器对象(register object) 以及局部静态对象(local static object)。区分这些对象的是对象所在存储区的属性和生命期。自动对象所在存储区从声明它的函数被调用时开始,一直到该函数结束为止。寄存器对象是一种自动对象它支持,对其值的快速存取。局部静态对象的存储区在该程序的整个执行期间一直存在。

当一个自动变量的地址被存储在一个生命期长于它的指针时,该指针被称为空悬指针(dangling pointer)。

在函数中频繁被使用的自动变量可以用register 声明来定义寄存器自动对象。
如果所选择的变量被频繁使用,则寄存器变量可以提高函数的执行速度。

动态分配的对象被分配在程序的空闲存储区的可用内存池中。
空闲存储区的第二个特点是分配的内存是未初始化的。
程序员用new 表达式创建动态分配的对象,用delete 表达式结束此类对象的生命期。

new 表达式是由关键字new 及其后面的类型指示符构成的,该类型指示符可以是内置类型或class类型。

auto_str需要注意:
1、不能用一个指向内存不是通过应用new 表达式分配的指针来初始化或赋值auto_ptr
2、不能让两个auto_ptr 对象拥有空闲存储区内同一对象的所有权

release()操作允许将一个auto_ptr 对象的底层对象初始化或赋位给第二个对象,而不会使两个auto_ptr 对象同时拥有同一对象的所有权。
get()操作返回底层对象的地址。
reset()操作重置一个auto_ptr 对象

对于用new 表达式分配的数组,只有第一维可以用运行时刻计算的表达式来指定。其他维必须是在编译时刻已知的常量值。

在空闲存储区创建的const 对象有一些特殊的属性:
1、const 对象必须被初始化
2、用 new 表达式返回的值作为初始值的指针必须是一个指向const 类型的指针
3、不能初始化用new 表达式创建的内置类型数组的元素

定位new 表达式(placement new expression):将对象创建在已经被分配好的内存中
必须包含头文件<new>

名字空间别名的声明,以关键字namespace 开头,后面是一个较短的别名,然后是赋值操作符,最后是原来的名字空间。

using 声明同其他声明的行为一样:它有一个域它引入的名字从该声明开始直到其所在的域结束都是可见的。
using 声明的特性:
1、它在该域中必须惟一
2、由外围域中的声明引入的相同名字被其隐藏
3、它被嵌套域中的相同名字的声明隐藏

函数重载的声明:
1、如果两个函数的参数表中参数的个数或类型不同,则认为这两个函数是重载的
2、如果两个函数的返回类型和参数表精确匹配,则第二个声明被视为第一个的重复声明
3、如果两个函数的参数表相同,但是返回类型不同,则第一个声明被视为第一个的错误重复声明,会被标记为编译错误。
4、如果在两个函数的参数表中,只有缺省实参不同,则第二个声明被视为第一个的重复声明。

程序员最好抱这样的观点:并不是每个语言特性都是你要攀登的下一座山峰,使用语言的特性应该遵从应用的逻辑,而不是简单地因为它的存在就必须要使用它。

重载函数集合中的全部函数都应在同一个域中声明。

由using 声明引入的函数重载了在该声明所出现的域中同名函数的其他声明。
如果using 声明向一个域中引入了一个函数,而该域中已经有同名函数且具有相同的参数表,则该using 声明就是错误的。

函数重载解析(function overload resolution) 是把函数调用与重载函数集合中的一个函数相关联的过程.
函数重载解析的步骤:
1 确定函数调用考虑的重载函数的集合确定函数调用中实参表的属性
2 从重载函数集合中选择函数,该函数可以在给出实参个数和类型的情况下用调用中指定的实参进行调用
3 选择与调用最匹配的函数

最佳可行函数是被适用于如下规则的函数
1 应用在实参上的转换不比调用其他可行函数所需的转换差
2 在某些实参上的转换要比其他可行函数对该参数的转换好

在精确匹配的等级类别中可能存在的转换如下:
1、从左值到右值的转换
2、从数组到指针的转换
3、从函数到指针的转换
4、限定修饰转换

限定修饰转换只应用在指针指向的类型上。当参数是const 或volatile 类型,而实参不是时,没有类型转换发生。
如果实参是指针,且有const 或volatile 限定符应用在指针上,依然没有类型转换。

转换被分成三组:提升(promotion)、 标准转换(standard conversion )、和用户定义的转换(user-defined conversions).

一个引用表示一个左值,所以当一个函数有一个引用参数时,被调用的函数接受一个左值。因此,不会有从左值到右值的转换被应用到相应的引用参数的实参上。

两个枚举类型在重载函数解析期间的行为可能完全不同,解析过程根据枚举常量的值来决定它们被提升的类型。

有五种转换属于标准转换:
1 整值类型转换:从任何整值类型或枚举类型向其他整值类型的转换(不包括前面提升部分中列出的转换)
2 浮点转换:从任何浮点类型到其他浮点类型的转换(不包括前面提升部分中列出的转换)
3 浮点—整值转换:从任何浮点类型到任何整值类型或从任何整值类型到任何浮点类型的转换
4 指针转换:整数值0 到指针类型的转换和任何类型的指针到类型void*的转换
5 bool 转换:从任何整值类型、浮点类型、枚举类型或指针类型到bool 型的转换

所有的标准转换都被视为是等价的。

因为枚举类型不是整型,仍为0 的枚举型值不能被转换成指针类型。

如果函数实参的类型是在一个名字空间中被声明的,则该名字空间中与被调用函数同名的成员函数也将被加入到候选函数集中。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值