===***8.2全局对象与函数***===
===8.2.1声明和定义===
在全局域中定义的对象,如果没有指定显式的初始值,则该存储区被初始化为0
extern 声明不会引起内存被分配,它可以在同一文件中或同一程序的不同文件中出现多次.
extern const double pi; //声明
既指定了关键字extern 又指定了一个显式初始值的全局对象声明,将被视为该对象的定义编译器将会为其分配存储区,而且该对象后续的定义都被标记为错误
extern const double pi = 3.1416; // 定义
符号常量定义以及inline 函数定义是特殊的定义,符号常量和inline 函数可以被定义多次
===8.2.2不同文件之间声明的匹配===
C++的一种机制:类型安全链接type-safe-linkage,通过它可以把函数参数的类型和数目编码在函数名,作用:
1、类型安全链接机制为文件之间的函数调用提供了类型检查手段
2、它对支持重载函数也是必需的
不同文件中出现的同一对象或函数声明的其他类型不匹配情况,在编译或链接时可能不会被捕捉到,因为***编译器一次只能处理一个文件***,它不能很容易地检查到文件之间的类型违例,这些类型违例可能是程序严重错误的根源,例如文件之间错误的对象声明或函数返问类型就不能被检测出来, 这样的错误只能在运行时刻异常或程序的错误输出中才能被揭示出来(使用头文件是防止此类错误的基本法则)
// token.C 中
unsigned char lastTok = 0;
unsigned char peekTok() { /* ... */ }
// lex.C 中
extern char lastTok; // 最后一个 token 这里如果程序中不使用时,编译时检查不出错误来
extern char peekTok(); // 查看 token 这里如果程序中不使用时,编译时检查不出错误来
===8.2.3头文件===
设计头文件有一些要注意的地方
1、编译头文件也需要时间
如果头文件过大或分散的元素太多,程序员可能会不愿意因为包含它而增加编译时间开销,为降低编译时间开销有些C++实现提供了预编译头文件支持
2、头文件不应该含有非inline 函数或对象的定义
因为这些定义如果在同一程序的两个或多个文件中被包含,就会产生重复定义的编译错误
由于符号常量(符号常量是任何const 型的对象)定义以及inline 函数定义是特殊的定义,符号常量和inline 函数可以被定义多次,所以可以定义在头文件中。
const char* msg = "?? oops: error: "; //msg不是符号常量
const char *const msg = "?? oops: error: "; //msg是符号常量
如果一个inline 函数将在多个文件中被用到,那么它必须被定义在头文件!
===8.4.3数组的动态分配与释放===
delete 表达式应用在值为0 的指针即不指向任何对象的指针上,不会引起任何麻烦下.
因为如果指针操作数被设置为0 则C++会保证delete 表达式不会调用操作符delete()
动态分配数组的主要好处是:它的第一维不必是常量值,即在编译时刻不需要知道维数
int dimension = strlen( errorTxt ) + 1;
char *str1 = new char[ dimension ]; //维数根据需要来确定
注意,对于用new 表达式分配的数组,只有第一维可以用运行时刻计算的表达式来指定。其他维必须是在编译时刻已知的常量值例如
// 分配一个二维数组
int (*pia3)[ 1024 ] = new int[ getDim() ][ 1024 ]; //ok
int **pia4 = new int[ 4 ][ getDim() ]; //错误
delete [] pia3; //注意只需要一个[]
Class A
{
A(){}
~A(){}
}
A *a = new A[10];//调用10次A()
delete [] a; //会调用10次~A()
delete a; //调用一次~A() (a[0]的析构函数)
注意new/delete、new[]/delete[]要配对:(下面摘自互联网http://topic.csdn.net/t/20010104/13/54861.html#)
在 c 語言裏,分配空間和釋放空間是用 malloc 和 free 的
如要分配 10 個 char ( char *a=( char * )malloc( 10 )
釋放則 free( a );
在 c++ 裏做同樣的事情,則 char *a=new char[ 10 ],
delete a;或者 c++ 裏真的有釋放數組要用 delete []
這樣的一個規定.
但為甚麼 c 裏能用一個指針去釋放一個數組,而 c++ 不能呢
事情當然不會是那樣了, c++ 是可以的就像上面那樣
delete a,告訴你一個事實,在 c++ 的 runtime Library
源程式碼裏實現 new 和 delete 是調用 malloc 和 free
的.但為甚麼要定義 delete [] 呢,那就是為了迎合 c++
的 class 的需要了.
在這裏你就要明白空間分配的情況了,當你分配標準類型時
( int char short long )
因為空間己經確定了,所以在系統的記憶體管理,可以用一個
指針就釋放一個數組,但是在 Class 裏,就不能了,
因為在 Class 裏,你自己可能又分配了空間,所以系統根本
不清楚你分配了多少空間,所以就無法為你釋放空間了.
因此 在 class 裏 有釋構函數,讓你去定義你要釋放的空間
然後讓系統去為你一次釋放.
(註:這裏講的系統不知道,是為說明問題,實際上系統是知道
你分配了多少空間的,不知道的是你究竟要釋放那些空間 )
所以在 c++ 裏釋放數組就要 delete [],用以去指明要調明
釋構函數,這當然如果你分配的是普通類型時,它就不會為你
調用釋構函數了,
因此當你分配普通類型的數組時,如 int *a=new[ 10 ];
那麼 delete a 和 delete [] a 是一樣的.
===8.4.4常量对象的动态分配与释放===
const int *pci = new const int(1024);
注意项:
1、const 对象必须被初始化(对于有缺省构造函数的类类型对象,初始值可以省略)
2、用 new 表达式返回的值作为初始值的指针必须是一个指向const 类型的指针,如pci
3、不能在空闲存储区内创建(即new创建)内置类型元素的const 数组,一个简单的原因是我们不能初始化用new 表达式创建的内置类型数组的元素
===8.4.5 定位new 表达式===
一种new的另类使用方法
这项设施允许程序员预分配大量的内存,供以后通过这种形式的new 表达式创建对象
必须包含头文件<new>
===8.5.6未命名名字空间===
swap在未命名名字空间中,从而函数swap()只在文件SortLib.C 中可见
在使用中,直接调用swap即可。
在引入标准C++名字空间之前解决此类声明局部化问题的常见方案是使用从C 语言中
继承来的关键字static (全局静态声明的用法)
static void swap( double *d1, double *d2 ) { /* ... */ } (与未命名名字空间等效)
随着越来越多的C++实现都支持名字空间,全局静态声明的用法将会被未命名的名字空间成员所取代