第9章 内存模型和名称空间
9.1单独编译
1,我们可以将组件函数放在独立的文件中。
2,一般我们将原来的程序分成三部分:
a>头文件:包含结构声明和使用这些结构的函数的原型。
b>源代码文件:包含与结构有关的函数的代码。
c>源代码文件:包含调用与结构相关的函数的代码。
头文件中的内容:
l 函数原型
l 使用#define或const定义的符号常量。
l 结构声明
l 类声明
l 模板声明
l 内联函数
结构声明只是告诉编译器如何创建该结构变量。所以可以放头文件中。
警告:在IDE中,不要将头文件加入到工程列表中,也不要再源代码文件中使用#include来包含其他源代码文件。同时#include”clrood.h”主意不要使用<>括号。
3,头文件管理
在同一个文件中只能将同一个头文件包含一次。记住这个规则很容易,然而很可能在不知情的情况下,将头文件包含多次。故我们可以采用c/c++技术可以避免多次包含头文件。它就是基于预处理编译指令#ifndef(if not defined)的。如下:
#ifndef COORDIN_H_
……
#endif
这意味着仅当以前没有使用预处理器编译指令#define定义名称COORDIN_H_,才处理#ifndef 和#endif之间的语句。
通常,使用#define语句来创建符号常量。如下:
#define MAXIMUM 4096
但只要将#define用于名称,就足以完成该名称的定义,如下:
#define COORDIN_H_
9.2存储持续性,作用域和链接性
9.2.1作用域和链接
作用域描述了名称在文件(翻译单元)的多大范围内可见。
链接性描述了名称如何在不同单元间共享。链接性为外部的名称可在文件间共享,链接性为内部的名称只能由一个文件中的函数共享。自动变量的名称没有链接性,因为他们不能共享。
C++变量的作用域:
a>局部变量
b>静态变量全局/局部(取决于如何被定义)
c>在名称空间中声明的变量的作用域为整个名称空间
c++函数的作用域:
a>整个类/整个名称空间
9.2.2自动存储持续性
自动变量只在包含他们的函数或代码块中可见。
2,自动变量和堆栈
自动变量的管理通常采用堆栈来进行管理。
堆栈是后进先出的存储结构。
3,寄存器变量
register关键字。自动变量,作用域局部,无链接性。
它提醒编译器,用户希望使用cpu寄存器,而不是堆栈来处理特定的变量,从而提供对变量的快速访问。(cpu访问寄存器的值比访问堆栈中的值要快)
提醒,希望,表示编译器不一定会满足上述要求。
注意:寄存器变量是没有内存地址的。如访问它的内存地址是错误操作。
9.2.3静态持续变量
1,c++为静态存储持续性变量提供了3种链接性:外部链接性,内部链接性和无链接性。这3种链接性都在整个程序执行期间存在,与自动变量相比,他们的寿命更长。使用固定的内存块来存储所有的静态变量。默认初始化为0。
2,如何创建这三种静态变量呢?
如上图,第一个注释语句为外部连接性,第二个为,内部链接性,第三个为没有链接性的静态变量。注意static的存在,和语句位置的不同,从而导致连接性不同。
同时,注意静态变量在整个程序执行期间都存在。第三条注释语句他知识作用域在funct1函数中,但是count变量却是存在在整个程序执行期间的。同时,第一条注释语句,他的链接性为外部,因此可以在程序的其他文件中使用它。
所有的静态持续变量都有下面两个特征:
a>未被初始化的静态变量的所有位都被设置为0;
b>只能使用常量表达式来初始化静态变量。常量表达式可以使用字面值常量,const常量,enum常量以及sizeof操作符。
1,静态持续性,外部链接性
答:用关键字extern来重新声明以前定义过的外部变量,我们在一个函数内部如果使用了extern double warn;来声明外部变量,则表明此函数内部的warn引用了外部变量。注意:这句话表明,函数内部的warn不可以初始化,(初始化是在分配的内存单元时给它赋值),但是很明显我们这里是一个引用过程,并没有给warn分配到内存单元。同时如果我们在函数内部定义了一个double warn;那么这将把全局变量隐藏起来,如果我们想使用全局变量warn,我们可以在函数内部中需要使用warn的地方,都改成::warn。即可。::是个作用域解析操作符。
在多文件程序中,可以在一个文件(且只能在一个文件)中定义一个外部变量。使用该变量的其他文件必须使用关键字extern声明它。
应使用外部变量在多个文件程序中不同部分之间共享数据,应使用连接性外内部的静态变量在同一个文件中的多个函数之间共享数据(名称空间提供了另外一种共享数据的方法,C++标准指出,使用static来创建内部链接性的方法就慢慢被淘汰)。
2,在谈const
在C++中,const限定符对默认储存类型稍有影响。在默认情况下全局变量的链接性为外部的,但const全局变量的链接性外内部的。也就是说,在C++看来全局const定义就像使用了static说明符一样。如果出于某种原因,我们希望某个常量的连接性为外部的,则可以使用extern关键字来覆盖默认的内部链接性:
extern cons tint states = 50;
在这种情况下,必须在所有使用该常量的文件中使用extern关键字来生命它。这与常规外部变量不同。同时const必须初始化。
9.2.5函数和链接性
1所有函数的存储持续性都自动为静态的。即在整个程序执行期间都一直存在。在默认情况下,函数的链接性为外部的,即可以在文件间共享。实际上,可以在函数原型中使用关键字extern来指出函数是在另一个文件中定义的,不过这是可选的额。。我们还可以使用关键字static将函数的链接性设置为内部的,使之只能在一个文件中使用。必须同时在原型和函数定义中都使用该关键字。
2,C++在哪里查找函数?
答:如果该文件中的函数原型指出该函数是静态的,则编译器将只在该文件中查找函数定义;否则,编译器(包括链接程序)将在所有的程序文件中查找。。如果找到两个定义,编译器将发出错误消息,因为每个外部函数只能有一个定义。如果在程序文件中没有找到,编译器将在库中进行搜索。
9.2.6语言链接性
9.2.7案和动态分配
1,new操作符得到的内存空间,不会被释放。
9.3布局new操作符
1,通常,new负责在堆(head)中找到一个足以能够满足要求的内存块。New操作符还有另一种变体,被称为布局new操作符,它让您能够指定要使用的位置,。程序员可能使用这种特性来设置其内存管理规程或处理需要通过特定地址进行访问的硬件。
2,如何布局new特性?
a>包含头文件new
b>将new操作符用与提供了所需地址的参数。
9.4名称空间
9.4.1传统的C++名称空间
1,声明区域:在函数外面声明全局变量,则声明区域为其声明所在的文件。对于函数中声明的变量,其声明区域为其声明所在的代码块。
2,潜在作用域:从声明点开始到其声明区域的结尾。因此潜在作用域比声明区域小。
9.4.2新的名称空间特性
1,通过定义一种新的声明区域来创建命名的名称空间,目的是提供一个声明名称的区域。一个名称空间中的名称不会与另外一个名称空间相同名称发生冲突,同时允许程序的其他部分使用该名称空间中声明的东西。例如:
名称空间可以是全局的,也可以位于另一个名称空间中,但不能位于代码块中。因此,默认情况下,在名称空间声明的名称的链接性为外部的(除非它引用了常量)。
第10章对象和类
10.1过程性编程和面向对象编程
1,首先从用户的角度考虑对象——描述对象所需的数据以及描述用户与数据交互所需的操作。完成对接口的描述后,需要确定如何实现接口和数据存储。
10.2抽象和类
1,成员函数的函数头使用作用域解析操作符(::)来指出函数所属的类。
2,方法可以访问类的私有成员。
3,内联方法:其定义位于类声明中的函数都将自动成为内联函数,因此Stock::set_tot()是一个内联函数。如果愿意,也可以在类声明之外定义成员函数,并使其成为内联函数。为此,只需要在类实现部分中定义函数时使用inline限定符即可
10.3类的构造函数和析构函数
1,默认构造函数和你可以重载此构造函数。构造函数被用来创建对象,而不能通过对象来调用。
2,析构函数:在对象过期时,析构函数完成清理工作。例如,如果构造函数使用new来分配内存,则析构函数将使用delete来释放这些内存。当然如果构造函数没有使用new,那析构函数实际上没有需要完成的任务。
在这种情况下,只需要昂编译器生成一个什么都不做的隐式析构函数即可。
析构函数原型:~Stock();
3,改进一个类
a>头文件:将构造函数和析构函数的原型加入到原来的类声明中。
b>实现文件
4,const成员函数
如下代码段:
const Stock land = Stock(“lsld”);
land.show();
对于C++来说,编译器将拒绝第二行。因为show()的代码 无法确保调用对象不被修改——调用对象和const一样,不应被修改。为了避免这个问题,我们可以将show()声明应改成下面这样:
void show() const;
同样函数定义的开头:
void stock::show()const
10.5对象数组
1,要创建类对象数组,则这个类必须有默认构造函数
10.7类作用域
1,在类声明中声明的枚举的作用域为整个类,因此可以用枚举为整形常量提供作用域为整个类的符号名称。还可以使用关键字static
10.8抽象数据类型
1,C++程序使用对战来管理自动变量。当新的自动变量被生成后,他们被添加到堆顶。消亡时,从堆栈中删除他们。