??xml version="1.0" encoding="utf-8" standalone="yes"?>
]]>
string和CString均是字符串模板类Qstring为标准模板类QSTLQ定义的字符串类Q已l纳入C++标准之中Q?br>
CStringQtypedef CStringT<TCHAR, StrTraitMFC<TCHAR>> CStringQؓVisual C++中最常用的字W串c,l承自CSimpleStringTc,主要应用在MFC和ATL~程中,主要数据cd有char(应用于ANSI)Qwchar_t(unicode)QTCHAR(ANSI与unicode均可)Q?br>
char*为C~程中最常用的字W串指针Q一般以’\0’为结束标志;
(? 构?/strong>
string是方便的Q可以从几乎所有的字符串构造而来Q包括CString和char*Q?br>
CStringơ之Q可以从基本的一些字W串变量构造而来Q包括char*{;
char*没有构造函敎ͼ仅可以赋|
举例Q?br>
char* psz = “joise”;
CString cstr( psz );
string str( cstr );
(? q算W重?/strong>
a) operator=
string是最方便的,几乎可以直接用所有的字符串赋|包括CString和char*Q?br>
CStringơ之Q可以直接用些基本的字符串赋|包括char*{;
char*只能由指针赋|q且是极危险的操作,使用strcpy或者memcpyQ而且char*在声明的时候如未赋初值徏议先设ؓNULLQ以避免野指针,令你抓狂Q?br>
举例Q?br>
char *psz = NULL;
psz = new char[10]; //当然Q以上的直接写成char *psz = new char[10];也是一?br>
memset( psz, 0, 10 );
strcpy( psz, “joise” );
CString cstr;
cstr = psz;
string str;
str = psz;
str = cstr;
delete []psz;
b) operator+
string与CString差不多,可以直接与char*q行加法Q但不可以相互?q算W,即string str = str + cstr是非法的Q须转换成char*Q?br>
char*没有+q算Q只能用strcat把两个指针连在一P
举例Q?br>
char* psz = “joise”;
CString cstr = psz;
cstr = cstr + psz;
string str = psz;
str = str + str + psz;
strcat( psz, psz );
strcat( psz, cstr );//合法
strcat( psz, str );//非法Q由此可见,CString可自动{换ؓconst char*Q而string不行
c) operator +=
string是最强大的,几乎可以与所有的字符串变?=Q包括CString和char*Q?br>
CStringơ之Q可以与基本的一些字W串变量q行+=而来Q包括char*{;
char*没有+=q算W,只能使用strcat把两个指针连在一P
d) operator[]
CString最好,当越界时会抛出断a异常Q?br>
string与char*下标界l果未定义;
举例Q?br>
char* psz = “joise”;
CString cstr = psz;
cout << cstr[8];
string str = psz;
cout << str[8];
cout << psz[8];
e) operator== 、operator!=、operator> 、operator< 、operator>= 、perator<=
CString与string之间不可以进行比较,但均可以与char*q行比较Qƈ且比较的是|而不是地址Q?br>
cout << ( psz == cstr );
cout << ( psz == str );
cout << ( str == psz );
cout << ( cstr == psz );//以上代码q回均ؓ1
(? 常用法
a) 查找
作用 | char* | string | CString |
查找指定?/td> | strchr strstr strrstr strspn |
find | Find |
W一个匹配的?/td> | fild_first_of | FindOneOf | |
从后面开始查?/td> | ReserveFind | ||
指定匚w方式 | find_if |
注:find_if中是把范围内的值挨个代入匹配函数直臌回true
b) 比较
作用 | char* | string | CString |
查找指定?区分大小? | strcmp strncmp strcoll _strncoll |
operator< operator> operator<= operator>= operator== operator!= |
Collate Compare |
查找指定?不区分大写) | _stricmp _strnicmp _stricoll _strnicoll |
CollateNoCase CompareNoCas |
注:q回值如?lt;0则前面的值小于后面的|反之亦然
c) 替换
作用 | char* | string | CString |
查找指定?/td> | _strset _strnset |
replace replace_copy replace_copy_if replace_if |
Replace |
d) 插入
作用 | char* | string | CString |
查找指定?/td> | insert | Insert |
作用 | char* | string | CString |
动态增加?/td> | strcat | push append |
Append AppendChar AppendFormat |
f) 截取
作用 | char* | string | CString |
得到部分?/td> | 用下标操?/td> | substr | Left Mid Right Truncate |
g) U除
作用 | char* | string | CString |
U除部䆾?/td> | remove | Remove | |
U除I白?/td> | RemoveBlanks 注:此ؓATL提供Q非C函数 |
remove_if | Trim TrimLeft TrimRig |
h) 转换大小?/p>
作用 | char* | string | CString |
转换大小?/td> | _strlwr _strupr |
MakeLower MakeUpper |
i) 与其他类型{?/p>
作用 | char* | string | CString |
转化为数?/td> | atoi atod atof |
Format | |
转化为char* | c_str | GetBuffer GetBufferSetLen |
j) 格式?/p>
作用 | char* | string | CString |
格式?/td> | sprintf | Format |
k) 得到长度
作用 | char* | string | CString |
得到长度 | strlen | length | GetLength |
得到大小 | size | GetAllocLength |
l) 判断为空
作用 | char* | string | CString |
判断是否为空 | 判断是否==NULL或者第一个字W是否是’\0’ | empty | IsEmpty |
m) 重定义大?/p>
作用 | char* | string | CString |
重定义大?/td> | realloc new |
resize | GetBufferSetLength |
n) 释放资源
作用 | char* | string | CString |
释放 | free delete (delete[]) |
ReleaseBuffer ReleaseBufferSetLength |
(? 安全?gt;
CString > string > char*Q?br>
(? 灉|?/strong>
CString > string >char*Q?br>
(? 可移植?/strong>
char* = string > CString
一?include “filename.h”?include filename.h>的区?/font>
#include “filename.h”是指~译器将从当前工作目录上开始查找此文g
#include filename.h>是指~译器将从标准库目录中开始查找此文g
二、头文g的作?/font>
加强安全?/font>
通过头文件可能方便地调用库功能,而不必关心其实现方式
三? , &修饰W的位置
对于*?amp;修饰W,Z避免误解Q最好将修饰W紧靠变量名
四、if语句
不要布变量与MD行比较,那会很容易出错的?/font>
整Ş变量必须要有cd相同的D行比?/font>
点变量最好少比点Q就要比也要有D行限?/font>
指针变量要和NULLq行比较Q不要和布尔型和整Ş比较
五、const?define的比?/font>
const有数据类型,#define没有数据cd
个别~译器中const可以q行调试Q?define不可以进行调?/font>
在类中定义常量有两种方式
1?在类在声明常量,但不赋|在构造函数初始化表中q行赋|
2?用枚举代替const帔R?/font>
六、C++函数中值的传递方?/font>
有三U方式:g?Pass by value)、指针传?Pass by pointer)、引用传?Pass by reference)
void fun(char c) //pass by value
void fun(char *str) //pass by pointer
void fun(char &str) //pass by reference
如果输入参数是以g递的话,最好用引用传递代替,因ؓ引用传递省M临时对象的构造和析构
函数的类型不能省略,q没有也要加个void
七、函C中的指针或引用常量不能被q回
Char *func(void)
{
char str[]=”Hello Word”;
//q个是不能被q回的,因ؓstr是个指定变量Q不是一般的|函数l束后会被注销?/font>
return str;
}
函数体内的指针变量ƈ不会随着函数的消亡而自动释?/font>
八、一个内存拷贝函数的实现?/font>
void *memcpy(void *pvTo,const void *pvFrom,size_t size)
{
assert((pvTo!=NULL)&&(pvFrom!=NULL));
byte *pbTo=(byte*)pvTo; //防止地址被改?/font>
byte *pbFrom=(byte*)pvFrom;
while (size-- >0)
pbTo++ = pbForm++;
return pvTo;
}
九、内存的分配方式
分配方式有三U,误住,说不定那天去面试的时候就会有人问你这问题
1?静态存储区Q是在程序编译时已l分配好的,在整个运行期间都存在Q如全局变量、常量?/font>
2?栈上分配Q函数内的局部变量就是从q分配的Q但分配的内存容易有限?/font>
3?堆上分配Q也U动态分配,如我们用new,malloc分配内存Q用delete,free来释攄内存?/font>
十、内存分配的注意事项
用new或malloc分配内存Ӟ必须要对此指针赋初倹{?/font>
用delete 或free释放内存后,必须要将指针指向NULL
不能修改指向帔R的指针数?/font>
十一、内容复制与比较
//数组……
char a[]=”Hello Word!”;
char b[10];
strcpy(b,a);
if (strcmp(a,b)==0)
{}
//指针……
char a[]=”Hello Word!”;
char *p;
p=new char[strlen(a)+1];
strcpy(p,a);
if (strcmp(p,a)==0)
{}
十二、sizeof的问?/font>
C一点,C++无法知道指针所指对象的大小Q指针的大小永远?字节
char a[]=”Hello World!”
char *p=a;
count sizeof(a) end; //12字节
count sizeof(p) endl; //4字节
而且Q在函数中,数组参数退化ؓ指针Q所以下面的内容永远输出?
void fun(char a[1000])
{
count sizeof(a) endl; //输出4而不?000
}
十三、关于指?/font>
1?指针创徏时必被初始?/font>
2?指针在free 或delete后必ȝ为NULL
3?指针的长度都?字节
Q、释攑ֆ存时Q如果是数组指针Q必要释放掉所有的内存Q如
char *p=new char[100];
strcpy(p,”Hello World”);
delete []p; //注意前面的EQ号
p=NULL;
Q、数l指针的内容不能过数组指针的最大容易?/font>
?
char *p=new char[5];
strcpy(p,”Hello World”); //报错 目标Ҏ不够?/font>
delete []p; //注意前面的EQ号
p=NULL;
十四、关于malloc/free 和new /delete
l malloc/free 是C/C+的内存分配符Qnew /delete是C++的内存分配符?/font>
l 注意Qmalloc/free是库函数Qnew/delete是运符
l malloc/free不能执行构造函C析构函数Q而new/delete可以
l new/delete不能在C上运行,所以malloc/free不能被淘?/font>
l 两者都必须要成对?/font>
l C++中可以用_set_new_hander函数来定义内存分配异常的处理
十五、E++的特?/font>
Q?+新增加有重蝲(overload)Q内联(inlineQ,ConstQVirtual四种机制
重蝲和内联:卛_用于全局函数Q也可用于类的成员函敎ͼ
Const和VirtualQ只可用于类的成员函敎ͼ
重蝲Q在同一cMQ函数名相同的函数。由不同的参数决定调用那个函数。函数可要不可要Virtual关键字。和全局函数同名的函C叫重载。如果在cM调用同名的全局函数Q必ȝ全局引用W号::引用?/font>
覆盖是指zcd数覆盖基cd?/font>
函数名相同;
参数相同Q?/font>
基类函数必须有Virtual关键字;
不同的范?zcd基类)?/font>
隐藏是指zcd蔽了基类的同名函数相?/font>
1?函数名相同,但参C同,此时不论基类有无Virtual关键字,基类函数被隐藏?/font>
2?函数名相同,参数也相同,但基cLVirtual关键?有就是覆?Q基cd数将被隐藏?/font>
内联Qinline关键字必M定义体放在一P而不是单单放在声明中?/font>
ConstQconst是constant的羃写,“恒定不变”的意思。被const修饰的东襉K受到强制保护Q可以预防意外的变动Q能提高E序的健壮性?/font>
1?参数做输入用的指针型参数Q加上const可防止被意外改动?/font>
2?按值引用的用户cd做输入参数时Q最好将按g递的改ؓ引用传递,q加上const关键字,目的是ؓ了提高效率。数据类型ؓ内部cd的就没必要做qg事情Q如Q?/font>
void Func(A a) 改ؓvoid Func(const A &a)?/font>
而void func(int a)没必要Ҏvoid func(const int &a);
3?l返回gؓ指针cd的函数加上constQ会使函数返回g能被修改Q赋l的变量也只能是const型变量。如Q函数const char*GetString(void); char *str=GetString()会出错。而const char *str=GetString()是正确的?/font>
4?Const成员函数是指此函C内只能调用Const成员变量Q提高程序的键壮性。如声明函数 int GetCount(void) const;此函C内就只能调用Const成员变量?/font>
VirtualQ虚函数Q派生类可以覆盖掉的函数Q纯虚函敎ͼ只是个空函数Q没有函数实CQ?/font>
十六、extern“C”有什么作用?
Extern “C”是由Q+Q提供的一个连接交换指定符P用于告诉Q+Q这D代码是Q函数。这是因为C++~译后库中函数名会变得很长,与C生成的不一_造成Q+Q不能直接调用C函数Q加上extren “c”后,C++p直接调用C函数了?/font>
Extern “C”主要使用正规DLL函数的引用和导出 ?在C++包含C函数或C头文件时使用。用时在前面加上extern “c” 关键字即可?/font>
十七、构造函C析构函数
zcȝ构造函数应在初始化表里调用基类的构造函敎ͼ
zcd基类的析构函数应加Virtual关键字?/font>
不要看构造函数和析构函数Q其实编hq是不容易?/font>
#include iostream.h>
class Base
{
public:
virtual ~Base() { cout "~Base" endl ; }
};
class Derived : public Base
{
public:
virtual ~Derived() { cout "~Derived" endl ; }
};
void main(void)
{
Base * pB = new Derived; // upcast
delete pB;
}
输出l果为:
~Derived
~Base
如果析构函数不ؓ虚,那么输出l果?/font>
~Base
十八?IFNDEF/#DEFINE/#ENDIF有什么作?/font>
仿止该头文g被重复引?/font>
一 const基础
如果const关键字不涉及到指针,我们很好理解Q下面是涉及到指针的情况Q?br>
int b = 500;
const int* a = &b; [1]
int const *a = &b; [2]
int* const a = &b; [3]
const int* const a = &b; [4]
如果你能区分Zq四U情况,那么Q恭喜你Q你已经q出了可喜的一步。不知道Q也没关p,我们可以参考《Effective c++》Item21上的做法Q如果const位于星号的左侧,则const是用来修饰指针所指向的变量,x针指向ؓ帔RQ如果const位于星号的右侧,const是修饰指针本nQ即指针本n是常量。因此,[1]和[2]的情늛同,都是指针所指向的内容ؓ帔RQconst攑֜变量声明W的位置无关Q,q种情况下不允许对内容进行更Ҏ作,如不?a = 3 Q[3]为指针本w是帔RQ而指针所指向的内容不是常量,q种情况下不能对指针本nq行更改操作Q如a++是错误的Q[4]为指针本w和指向的内容均为常量?br>另外const 的一些强大的功能在于它在函数声明中的应用。在一个函数声明中Qconst 可以修饰函数的返回|或某个参敎ͼ对于成员函数Q还可以修饰是整个函数。有如下几种情况Q以下会逐渐的说明用法:
A& operator=(const A& a);
void fun0(const A* a );
void fun1( ) const; // fun1( ) 为类成员函数
const A fun2( );
?const的初始化
先看一下const变量初始化的情况
1) 非指针const帔R初始化的情况Q?br>
A b;
const A a = b;
2) 指针(引用)const帔R初始化的情况Q?br>
A* d = new A();
const A* c = d;
或者:const A* c = new A();
引用Q?br>A f;
const A& e = f; // q样作e只能讉K声明为const的函敎ͼ而不能访问一般的成员函数Q?br>
[思?]Q?以下的这U赋值方法正吗Q?br>const A* c=new A();
A* e = c;
[思?]Q?以下的这U赋值方法正吗Q?br>A* const c = new A();
A* b = c;
?作ؓ参数和返回值的const修饰W?br>
其实Q不论是参数q是q回|道理都是一LQ参C入时候和函数q回的时候,初始化const变量
1 修饰参数的constQ如 void fun0(const A* a ); void fun1(const A& a);
调用函数的时候,用相应的变量初始化const帔RQ则在函C中,按照const所修饰的部分进行常量化Q如形参为const A* aQ则不能对传递进来的指针的内容进行改变,保护了原指针所指向的内容;如Ş参ؓconst A& aQ则不能对传递进来的引用对象q行改变Q保护了原对象的属性?br>[注意]Q参数const通常用于参数为指针或引用的情?
2 修饰q回值的constQ如const A fun2( ); const A* fun3( );
q样声明了返回值后Qconst按照"修饰原则"q行修饰Qv到相应的保护作用?br>
const Rational operator*(const Rational& lhs, const Rational& rhs)
{
return Rational(lhs.numerator() * rhs.numerator(),
lhs.denominator() * rhs.denominator());
}
q回值用const修饰可以防止允许q样的操作发?
Rational a,b;
Radional c;
(a*b) = c;
一般用const修饰q回gؓ对象本nQ非引用和指针)的情况多用于二目操作W重载函数ƈ产生新对象的时候?br>[ȝ] 一般情况下Q函数的q回gؓ某个对象Ӟ如果其声明为constӞ多用于操作符的重载。通常Q不用const修饰函数的返回值类型ؓ某个对象或对某个对象引用的情c?br>原因如下Q?br>如果q回gؓ某个对象为constQconst A test = A 实例Q或某个对象的引用ؓconstQconst A& test = A实例Q,则返回值具有const属性,则返回实例只能访问类A中的公有Q保护)数据成员和const成员函数Qƈ且不允许对其q行赋值操作,q在一般情况下很少用到?br>
[思?]Q?q样定义赋值操作符重蝲函数可以吗?
const A& operator=(const A& a);
?cL员函Cconst的?br>
一般放在函C后,形如Qvoid fun() const;
如果一个成员函数的不会修改数据成员Q那么最好将其声明ؓconstQ因为const成员函数中不允许Ҏ据成员进行修改,如果修改Q编译器报错,q大大提高了E序的健壮性?br>
?使用const的一些徏?br>
1 要大胆的使用constQ这给你带来无的益处Q但前提是你必须搞清楚原委;
2 要避免最一般的赋值操作错误,如将const变量赋|具体可见思考题Q?br>3 在参C使用const应该使用引用或指针,而不是一般的对象实例Q原因同上;
4 const在成员函C的三U用法(参数、返回倹{函敎ͼ要很好的使用Q?br>5 不要L的将函数的返回值类型定为const;
6除了重蝲操作W外一般不要将q回值类型定为对某个对象的const引用;
[思考题{案]
1 q种Ҏ不正,因ؓ声明指针的目的是Z对其指向的内容进行改变,而声明的指针e指向的是一个常量,所以不正确Q?br>2 q种Ҏ正确Q因为声明指针所指向的内容可变;
3 q种做法不正;
在const A::operator=(const A& a)中,参数列表中的const的用法正,而当q样q箋赋值的时侯Q问题就出现了:
A a,b,c:
(a=b)=c;
因ؓa.operator=(b)的返回值是对a的const引用Q不能再c赋值给const帔R?/p>
int n=9; double d=static_cast < double > (n);
上面的例子中, 我们一个变量从 int 转换?double. q些cd的二q制表达式是不同? 要将整数 9 转换?双精度整?9, static_cast 需要正地为双_ֺ整数 d 补比特? 其结果ؓ 9.0. reinterpret_cast 的行为却不同:
int n=9;
double d=reinterpret_cast<double & > (n);
q次, l果有所不同. 在进行计以? d 包含无用? q是因ؓ reinterpret_cast 仅仅是复?n 的比特位?d, 没有q行必要的分?
因此, 你需要}慎?reinterpret_cast.
reinterpret_casts的最普通的用途就是在函数指针cd之间q行转换。例如,假设你有一个函数指针数l:
typedef void (*FuncPtr)(); // FuncPtr is 一个指向函?br /> // 的指针,该函数没有参?br /> // q回值类型ؓvoid
FuncPtr funcPtrArray[10]; // funcPtrArray 是一个能容纳
// 10个FuncPtrs指针的数l?br />让我们假设你希望Q因为某些莫名其妙的原因Q把一个指向下面函数的指针存入funcPtrArray数组Q?br />int doSomething();
你不能不l过cd转换而直接去做,因ؓdoSomething函数对于funcPtrArray数组来说有一个错误的cd。在FuncPtrArray数组里的函数q回值是voidcdQ而doSomething函数q回值是intcd?br />funcPtrArray[0] = &doSomething; // 错误Q类型不匚w
reinterpret_cast可以让你qɾ~译器以你的Ҏȝ待它们:
funcPtrArray[0] = // this compiles
reinterpret_cast<FuncPtr>(&doSomething);
转换函数指针的代码是不可UL的(C++不保证所有的函数指针都被用一LҎ表示Q,在一些情况下q样的{换会产生不正的l果Q参见条ƾM31Q,所以你应该避免转换函数指针cdQ除非你处于着背水一战和刀架喉的危急时刅R?/p>
[1] 在编写程序时Q你是在Z针对某个问题的解x案中的思想建立起一U具体表C。让E序的结构尽可能地直接反映这些思想Q?br /> [a] 如果你能把“它”看成一个独立的概念Q就把它做成一个类?br /> [b] 如果你能把“它”看成一个独立地实体Q就把它做成某个cȝ一个对象?br /> [c] 如果两个cL共同的界面,此界面做成一个抽象类?br /> [d] 如果两个cȝ实现有某些显著的共同东西Q静q些共性做成一个基cR?br /> [e] 如果一个类是一U对象的容器Q将它做成一个模ѝ?br /> [f] 如果一个函数实现对某容器的一个算法,它实现为对一族容器可用的模板函数?br /> [g] 如果一l类、模板等互相之间有逻辑关系Q将它们放进一个名字空间力?br />[2] 在你定义一个ƈ不是实现某个像矩阉|复数q样的数学对象的cLQ或者定义一个低层地cd如链接表的时候:
[a] 不要使用全局数据Q用成员)?br /> [b] 不要使用全局函数?br /> [c] 不要使用公用数据成员?br /> [d] 不要使用友元Q除非ؓ了避免[a]或[c]?br /> [e] 不要在一个类里面䏀类型域”;采用虚函数?br /> [f] 不要使用在线函数Q除非位效果显著的优化?/p>
W??C++概览
[1] 不用x,一切都会随着旉的推U而逐渐明朗h?br />[2] 你ƈ不需要在知道了C++地所有细节之后才能写出好的C++E序?br />[3] L别关注程序设计技术,而不是各U语a特征?/p>
W??标准库概?/p>
[1] 不要像重新发明R轮那样企囑ց每g事;M用库?br />[2] 不要怿奇迹Q要理解你的库能做什么,它们如何做,它们做时需要多大代仗?br />[3] 当你遇到一个选择Ӟ应该优先选择标准库而不是其他的库?br />[4] 不要认ؓ标准库对于Q何事情都是最理想的?br />[5] 切记#include你所用到的功能的头文件?br />[6] CQ标准库的功能定义在名字I间std中?br />[7] LstringQ而不是char*?br />[8] 如果怀疑,q一个检查区间范围的向量?br />[9] vector<T>、list<T>和map<key, value>都比T[]好?br />[10] 如果要向一个容器中d一个元素,用push_back()或back_insert()?br />[11] 采用对vector的push_back()Q而不是realloc()?br />[12] 在main()中捕捉公q异常?/p>
W??cd和声?/p>
[1] 保持较小的作用域?br />[2] 不要在一个作用域和它外围的作用域里采用同L名字?br />[3] 在一个声明中Q只Q声明一个名字?br />[4] 让常用的和局部的名字比较短,让不常用的和全局的名字比较长?br />[5] 避免看v来类似的名字?br />[6] l持某种l一的命名风根{?br />[7] 仔细选择名字Q反映其意义而不是反映实现方式?br />[8] 如果所用的内部cd表示某种可能变化的|Ltypdef为它定义一个有意义的名字?br />[9] 用typedef为类型定义同义词Q用枚D或类d义新cd?br />[10] 切记每个声明中都必须描述一个类型(没有隐式的intQ?br />[11] 避免有关字符值的不必要的假设?br />[12] 避免有关整数大小的不必要假设?br />[13] 避免有关点cd表示范围的不必要假设?br />[14] 优先使用普通的int而不是short int或者long int?br />[15] 优先使用double而不是float或者long double?br />[16] 优先使用普通的char而不是signed char或者unsigned char?br />[17] 避免做出有关对象大小的不必要假设?br />[18] 避免无符L术?br />[19] 应该带着疑问ȝ待从signed到unsignedQ或者从unsigned到singed的{换?br />[20] 应该带着疑问ȝ待从点到整数的转换?
[21] 应该带着疑问其看待向较小cd的{换,如将int转换到char?/p>
W??指针、数l和l构
[1] 避免非^凡的指针术?br />[2] 当心Q不要超出函数的界限d?br />[3] 量使用0而不是NULL?br />[4] 量使用vector和valarrray而不是内部(C风格Q的数组?br />[5] 量使用string而不是以0l尾的char数组?br />[6] 量用普通的引用参数?br />[7] 避免void*Q除了在某些低代理?br />[8] 避免在代码中使用非^凡的文字量(“神U的数”)。相反,应该定义和用各U符号常量?/p>
W??表达式和语句
[1] 应尽量可能用标准库Q而不是其他的库和“手工打造的代码”?br />[2] 避免q于复杂的表辑ּ?br />[3] 如果对运符的优先有疑问,加括受?br />[4] 避免昑ּcd转换?br />[5] 若必d昑ּcd转换Q提倡用特D强制运符Q而不是C风格的强制?br />[6] 只对定义良好的构造用T(e)记法?br />[7] 避免带有无定义求值顺序的表达式?br />[8] 避免goto?br />[9] 避免do语句?br />[10] 在你已经有了d始化某个变量的g前,不要d明它?br />[11] 式注释简z、清晰、有意义?br />[12] 保持一致的~进~排风格?br />[13] 們于去定义一个成员函数operator new()d代全局的operator new()?br />[14] 在读输入的时候,d考虑病态Ş式的输入?/p>
W??函数
[1] 质疑那些非const的引用参敎ͼ如果你想要一个函数去修改其参敎ͼ请用指针或者返回倹{?br />[2] 当你需要尽可能减少参数复制Ӟ应该使用const引用参数?br />[3] q泛而一致地使用const?br />[4] 避免宏?br />[5] 避免不确定数目的参数?br />[6] 不要q回局部变量的指针或者引用?br />[7] 当一些函数对不同的类型执行概念上相同的工作时Q请使用重蝲?br />[8] 在各U整C重蝲Ӟ通过提供函数L除常见的歧义性?br />[9] 在考虑使用指向函数的指针时Q请考虑虚函数或模板是不是更好的选择?br />[10] 如果你必M用宏Q请使用带有许多大写字母的丑陋的名字?/p>
W??名字I间和异?/p>
[1] 用名字空间表C逻辑l构?br />[2] 每个非局部的名字攑օ某个名字I间里,除了main()之外?br />[3] 名字I间的设计应该让你能很方便地使用它,而又不会意外地访问了其他的无兛_字空间?br />[4] 避免对名字空间用很短的名字?br />[5] 如果需要,通过名字I间别名ȝ和和长名字空间的影响?br />[6] 避免l你的名字空间的用户d太大的记法负担?br />[7] 在定义名字空间的成员时用namespace::member的Ş式?br />[8] 只在转换Ӟ或者在局部作用域里,才用using namespace?br />[9] 利用异常L弛“错误”处理代码和正常处理代码之间的联pR?br />[10] 采用用户定义cd作ؓ异常Q不用内部类型?br />[11] 当局部控制结构以应付问题,不要使用异常?/p>
W??源文件和E序
[1] 利用头文件去表示界面和强调逻辑l构?br />[2] ?include头文g包含到实现有兛_能的源文仉?br />[3] 不要在不同编译单位里定义h同样名字Q意义类g又不同的全局变量?br />[4] 避免在头文g里定义非inline函数?br />[5] 只在全局作用域或名字I间里?include?br />[6] 只用#include包含完整的定义?br />[7] 使用包含保护W?br />[8] ?includeC头文件包含到名字I间里,以避免全局名字?br />[9] 头文g做成自给自的?br />[10] 区分用户界面和实现界面?br />[11] 区分一般用L面和专家用户界面?br />[12] 在有意向用于非C++E序l成部分的代码中Q应避免需要运行时初始化的非局部对象?/p>
W?0?c?/p>
[1] 用类表示概念?br />[2] 只将public数据QstructQ用在它实际杀q那仅仅时数据,而且对于q些数据成员q不存在不变式的地方?br />[3] 一个具体类型属于最单的cR如果有用的话,应该尽可能使用具体cdQ而不要采用更复杂的阿里,也不要用单的数据l构?br />[4] 只将那些需要直接访问类的表C的函数作ؓ成员函数?br />[5] 采用名字I间QɾcM其协助函C间的关系更明?br />[6] 那些不修改对象值的成员函数做成const成员函数?br />[7] 那些需要访问类的表C,但无针对特定对象调用的成员函数做成static成员函数?br />[8] 通过构造函数徏立vcȝ不变式?br />[9] 如果构造函数申hU资源,析构函数应该释放一资源?br />[10] 如果在一个类里有指针成员Q它p有复制操作(包括复制构造函数和复制赋|?br />[11] 如果在一个类里有引用成员Q它可能需要有复制操作Q包括复制构造函数和复制赋|?br />[12] 如果一个类需要复制操作或析构函数Q它多半q需要有构造函数、析构函数、复制赋值函数和复制构造函数?br />[13] 在复制赋值函数里需要检查自我赋倹{?br />[14] 在写复制构造函数时Q请心地复制每个需要复制的元素Q当心默认的初始式)?br />[15] 在向某个cMd新成员函数时Q一定要仔细查,看是否存在需要更新的用户定义构造函敎ͼ以它能够初始化新成员?br />[16] 在类声明中需要定义整型常量时Q请使用枚D?br />[17] 在构造全局的和名字I间的对象时Q应避免序依赖性?br />[18] 用第一ơ开兛_~和序依赖性问题?br />[19] 误住,临时对象在建立它们的那个完整表辑ּl束旉毁?/p>
W?1?q算W重?/p>
[1] 定义q算W主要是Z模仿习惯使用方式?br />[2] 对于大型q算对象Q请使用const引用参数cd?br />[3] 对于大型的结果,误虑优化q回方式?br />[4] 如果默认复制操作对一个类和合适,最好是直接用它?br />[5] 如果默认复制操作对一个类不和合适,重新定义它,或者禁止它?br />[6] 对于需要访问表C的操作Q优先考虑作ؓ成员函数而不是作为非成员函数?br />[7] 对于不访问表C的操作Q优先考虑作ؓ非成员函数而不是作为成员函数?br />[8] 用名字空间将协助函数与“它们的”类兌h?br />[9] 对于对称的运符采用非成员函数?br />[10] ?)作ؓ多维数组的下标?br />[11] 只有一个“大参数”的构造函数做成explicit?br />[12] 对于非特D的使用Q最好是用标准string而不是你自己的练习?br />[13] 要注意引q隐式{换的问题?br />[14] 用成员函数表N些需要左g为其左运对象的q算W?/p>
W?2?zc?/p>
[1] 避免cd域?br />[2] 用指针和引用避免切割问题?br />[3] 用抽象类设计的中心集中到提供清晰的界面斚w?br />[4] 用抽象类是界面最化?br />[5] 用抽象类从界面中排除实现l节?br />[6] 用虚函数是新的实现能够添加进来,又不会媄响用户代码?br />[7] 用抽象类d可能减少用户代码的重新编译?br />[8] 用抽象类是不同的实现能够共存?br />[9] 一个有虚函数的cd该有一个虚析构函数?br />[10] 抽象c通常不需要构造函数?br />[11] 让不同概늚表示也不同?/p>
W?3?模板
[1] 用模板描q需要用到许多参数cd上去的算法?br />[2] 用模板表q容器?br />[3] 为指针的容器提供专门化,以减代码规模?br />[4] L在专门化之前声明模板的一般Ş式?br />[5] 在专门化的用之前先声明它?br />[6] 量减少模板定义对于实例化环境的依赖性?br />[7] 定义你所声明的每一个专门化?br />[8] 考虑一个模板是否需要有针对C风格字符串和数组的专门化?br />[9] 用表q策略的对象q行参数化?br />[10] 用专门化和重载ؓ同一概念的针对不同类型的实现提供l一界面?br />[11] 为简单情冉|供简单界面,用重载和默认参数去表qC常见的情c?br />[12] 在修改ؓ通用模板之前Q在具体实例上排除程序错误?br />[13] 如果模板定义需要在其他~译单位里访问,误住写export?br />[14] 对大模板和带有非q_环境依赖性的模板Q应采用分开~译的方式?br />[15] 用模板表C{换,但要非常心地定义这些{换?br />[16] 如果需要,用constraint()成员函数l模板的实参增加限制?br />[17] 通过昑ּ实例化减编译和q接旉?br />[18] 如果q行时的效率非常重要Q那么最好用模板而不是派生类?br />[19] 如果增加各种变Ş而又不重新编译是很重要的Q最好用zc而不是模ѝ?br />[20] 如果无法定义公共的基c,最好用模板而不是派生类?br />[21] 当有兼容性约束的内部cd和结构非帔R要时Q最好用模板而不是派生类?/p>
W?4?异常处理
[1] 用异常做错误处理?br />[2] 当更局部的控制机构以应付Ӟ不要使用异常?br />[3] 采用“资源申请即初始化”技术去理资源?br />[4] q不是美国程序都要求h异常时的安全性?br />[5] 才用“资源申请即初始化”技术和异常处理器去l持不变式?br />[6] 量用try块,用“资源申请即初始化”技术,而不是显式的处理器代码?br />[7] q不是美国函数都需要处理每个可能的错误?br />[8] 在构造函数里通过抛出异常指明出现p|?br />[9] 在从赋g抛出异常之前Q式操作对象处于合法状态?br />[10] 避免从析构函数里抛出异常?br />[11] 让main()捕捉q报告所有的异常?br />[12] 使正常处理代码和错误处理代码怺分离?br />[13] 在构造函数里抛出异常之前Q应保证释放在此构造函数里甌的所有资源?br />[14] 使资源管理具有层ơ性?br />[15] 对于主要界面使用异常描述?br />[16] 当心通过new分配的内存在发生异常时没有释放,q由此而导致存储的失?br />[17] 如果一函数可能抛出某个异常Q就应该假定它一定会抛出q个异常?br />[18] 不要假定所有异帔R时由excepioncL生出来的?br />[19] 库不应该单方面终止程序。相反,应该抛出异常Q让调用者去做决定?br />[20] 库不应该生成面向最l用L错误信息。相反,它应该抛出异常,让调用者去做决定?br />[21] 在设计的前期开发出一U错误处理策略?/p>
W?5?cdơ结?/p>
[1] 利用常规的多重承表q特征的合ƈ?br />[2] 利用多重l承完成实现l节与界面分R?br />[3] 用virtual基类表达在类层次l构里对某些c(不是全部c)共同的东ѝ?br />[4] 避免昑ּ的类型{换(强制Q?br />[5] 在不可避免地需要O游类层次l构的地方,使用dynamic_cast?br />[6] 量使用dynamic_cast而不是typeid?br />[7] 量使用private而不是protected?br />[8] 不要声明protected数据成员?br />[9] 如果某个cd义了operator delete()Q它也应该有虚析构函数?br />[10] 在构造和析构期间不要调用虚函数?br />[11] 量用析成员名而写的显式限定词Q最好时在覆盖函数里用它?/p>
W?6?库组l和容器
[1] 利用标准库功能,以维持可UL性?br />[2] 决不要另行定义标准库的功能?br />[3] 决不要认为标准库比什么都好?br />[4] 在定义一U新功能Ӟ应考虑它是否能U_标准库所提供的框架中?br />[5] C标准库功能都定义在名字空间std里?br />[6] 通过包含保准卡头文g声明其功能,不要自己另行昑ּ声明?br />[7] 利用后箋抽象的优炏V?br />[8] 避免肥大的界面?br />[9] 与自己写按照反向序的显式@环相比,最好是写利用反向P代器的算法?br />[10] 用base()从reverse_iterator抽取出iterator?br />[11] 通过引用传递容器?br />[12] 用P代器cdQ如list<char>::iteratorQ而不要采用烦引容器元素的指针?br />[13] 在不需要修改容器元素时Q用constq代器?br />[14] 如果希望查访问范_P直接或间接)使用at()?br />[15] 多用容器和push_back()或resize()Q少用数l和realloc().
[16] vector改变大小之后Q不要用指向其中的q代器?br />[17] 利用reserve()避免使P代器非法?br />[18] 在需要的时候,reserve()可以使执行情冉|Ҏ预期?/p>
W?7?标准库容?/p>
[1] 如果要用容器Q首先考虑用vector?br />[2] 了解你经怋用的每个操作的代P复杂性,大O度量Q?br />[3] 容器的界面、实现和表示使不同的概念Q不要淆?br />[4] 你可以依据多U不同准则去排序和搜索?br />[5] 不要用C风格的字W串作ؓ关键码,除非你提供了一U适当的比较准则?br />[6] 你可以定义这L比较准则Qɽ{h的但是不相同的关键码值映到同一个关键码?br />[7] 在插入和删除元素Ӟ最好时使用序列末端的操作(back操作Q?br />[8] 当你需要在容器的前端或中间做许多插入和删除ӞLlist?br />[9] 当你主要通过关键码访问元素时Q请用map或multimap?br />[10] 量用最的操作集合Q以取得最大的灉|性?br />[11] 如果要保持元素的序性,选用map而不是hash_map?br />[12] 如果查找速度极其重要Q选hash_map而不是map?br />[13] 如果无法对元素定义小于操作时Q选hash_map而不是map?br />[14] 当你需要检查某个关键码是否在关联容器里的时候,用find()?br />[15] 用equal_range()在关联容器里扑և所有具有给定关键码的所有元素?br />[16] 当具有同样关键码的多个值需要保持顺序时Q用multimap?br />[17] 当关键码本n是你需要保存的值时Q用set或multiset?/p>
W?8?法和函数对?/p>
[1] 多用法Q少用@环?br />[2] 在写循环Ӟ考虑是否能将它表qCؓ一个通用的算法?br />[3] 常规性地重温法集合Q看卡是不是能将新应用变得更明晰?br />[4] 保证一对P代器参数实表述了一个序列?br />[5] 设计时应该让使用最频繁的操作时单而安全的?br />[6] 吧测试表q成能够作ؓ谓词使用的Ş式?br />[7] 切记谓词是函数和对象Q不是类型?br />[8] 你可以用U束器从二元谓词做出一元谓词?br />[9] 利用mem_fun()和mem_fun_ref()算法应用于容器?br />[10] 当你需要将一个参数约束到一个函CӞ用ptr_fun()?br />[11] 切记srrcmp()?表示“相{”,?=不同?br />[12] 仅在没有更特D的法Ӟ才用for_each()和tranform()?br />[13] 利用谓词Q以便能一各种比较准则和相{准则用算法?br />[14] 利用谓词和其他函数对象,以标准法能用于表C围广泛的意义?br />[15] q算W?lt;?=在指针上的默认意义很适用于标准算法?br />[16] 法q不直接为它们的参数序列增加或减元素?br />[17] 应保证用于同一个序列的于和相{谓词相互匹配?br />[18] 有时排好序的序列用v来更有效且优雅?br />[19] 仅ؓ兼容性而用qsort()和bsearch()?/p>
W?9?q代器和分配?/p>
[1] 在写一个算法时Q设法确定需要用哪种q代器才能提供可接受的效率,qӞ只)使用q种q代器所支持的操作符去表q算法?br />[2] 当给定的q代器参数提供了多于法所需 的最支持时Q请通过重蝲法提供效率更高的实现?br />[3] 利用istream_traitsZ同P代器cd描述适当的算法?br />[4] C在istream_iterator和ostream_iterator的访问之前?+?br />[5] 用插入器避免容器溢出?br />[6] 在排错时使用额外的检查,后面只在必须时才删除q些查?br />[7] 多用++pQ少用p++?br />[8] 使用未初始化的存储去改善那些扩展数据l构的算法性能?br />[9] 使用临时~冲区去改善需要时数据结构的法的性能?br />[10] 在写自己的分配器之前三思?br />[11] 避免malloc()、free()、realloc(){?br />[12] 你可以通过为rebind所用的技术去模拟Ҏ板的typedef?/p>
W?0??/p>
[1] 量使用string操作Q少用C风格字符串函数?br />[2] 用string作ؓ变量或者成员,不作为基cR?br />[3] 你可以将string作ؓ参数值或者返回|让系l去兛_存储理问题?br />[4] 当你希望做范围检查时Q请用at()而不是P代器或者[]?br />[5] 当你希望优化速度ӞLq代器或[]而不是at()?br />[6] 直接或者间接地使用substr()去读字子Ԍ用replace()d子串?br />[7] 用find()操作在string里确定值的位置Q而不是写一个显式的循环Q?br />[8] 在你需要高效率地添加字W时Q请在string的后面附加?br />[9] 在没有极端时间要求情况下用string作ؓ字符输入的目标?br />[10] 用string::npos表示“sring的剩余部分”?br />[11] 如果必要Q就采用低操作d现极度频J用的strngQ而不是到处用低数据l构Q?br />[12] 如果你用stringQ请在某些地Ҏ捉length_error和out_of_rang异常?br />[13] 心Q不要将带?的char*传递给字符串函数?br />[14] 只是到必d的时候,Q再Q用c_str()产生string的C风格表示?br />[15] 当你需要知道字W串的类别时Q用isalpha()、isdigit(){函敎ͼ不要自己d对字W值的?/p>
W?1??/p>
[1] 在ؓ用户定义cd的值定?lt;<?gt;>Ӟ应该采用意义清晰的正文表辑Ş式?br />[2] 在打印包含低优先U运符的表辑ּ旉要用括号?br />[3] 在添加新?lt;<?gt;>q算W时Q你不必修改istream或ostream?br />[4] 你可以定义函敎ͼ时其能基于第二个Q或更后面的Q参敎ͼh像virtual函数那样的行为?br />[5] 切记Q按默认U定>>跌所有空根{?br />[6] 使用低输入函数Q如get()和read()Q主要是Z实现高输入函数?br />[7] 在用get()、getline()和read()时留心其l止准则?br />[8] 在控制I/OӞ量采用操控W,用状态标志?br />[9] Q只Q用异常L捉罕见的I/O错误?br />[10] 联结用于交互式I/O的流?br />[11] 使用哨位许多函数的入口和出口代码集中到一个地斏V?br />[12] 在无参数操控W最后不要写括号?br />[13] 使用标准操控W式应记住写#include <iomanip>?br />[14] 你可以通过定义一个简单函数对象得C元运符的效果(和效率)?br />[15] 切记Qwidth描述只应用于随后的一个I/O操作?br />[16] 切记precision描述只对所后所的QҎ输出操作有效?br />[17] 用字W串做内存里的格式化?br />[18] 你可以描qC个文件流的模式?br />[19] 在扩充I/OpȝӞ应该清楚地区分格式化QiostreamQ和~冲QstreambufQ?br />[20] 传输值的非标准方式实Cؓ缓册Ӏ?br />[21] 格式化值的非标准方式实Cؓ操作?br />[22] 你可以利用一对函数隔d装其对用户定义代码的调用?br />[23] 你可以在d之前用in_avail()ȝ定输入操作是否会被阻塞?br />[24] 划分清楚需要高效的单操作和实现某种{略的操作(前者做成inlineQ将后者做成virtualQ?br />[25] 用locale“文化差异”局部化?br />[26] 用sync_with_stdio(x)L合C风格和C++风格的I/OQ或者离解C风格和C++风格的I/O?br />[27] 当心C风格I/O的类型错误?/p>
W?2?数?/p>
[1] 数值问题常常和微妙。如果你Ҏ值问题的数学斚w不是100%有把握,请去找专家或者做试验?br />[2] 用numberic_limitsȝ定内部类型的性质?br />[3] 为用户定义的标量cd描述numberic_limits?br />[4] 如果q行时效率比对于操作和元素的灉|性更重要的话Q那么请用valarrayd数D?br />[5] 用切割表q在数组的一部分上的操作Q而不是用循环?br />[6] 利用l合器,通过清除临时量和更好的算法来获得效率?br />[7] 用std::complex做复数算术?br />[8] 你可以把使用complexcȝ老代码通过一个typedef转ؓ用str::complex模板?br />[9] 在写循环从一个表出发计算某个g前,先考虑一下accumulate()、inner_produce()、partial_sum()和adjacent_difference()?br />[10] 最好用具有特定分布的随机敎ͼ直接用rand()?br />[11] 注意是你的随机数充分随机?/p>
W?3?开发和设计
[1] 知道你试图达C么目的?br />[2] 心中牢记软g开发是一h的活动?br />[3] 用类比来证明是有意的ƺ骗?br />[4] 保持一个特定的实实在在的目标?br />[5] 不要试图用技术方式去解决C会问题?br />[6] 在设计和对待人员斚w都应该有长期考虑?br />[7] 对于什么程序在~码之前先行设计是有意义的,在程序规模上q没有下限?br />[8] 设计q程应鼓励反馈?br />[9] 不要做事情都当做取得了q展?br />[10] 不要推广到超Z所需要的、你已有直接l验的和已经试q的东西?br />[11] 概念表qCؓcR?br />[12] pȝ里也存在一些不应该用类表述的性质?br />[13] 概念间的层ơ关pȝcdơ结构表C?br />[14] d到应用和实现中去L概念间的共性,由此得到的一般性概念表CZؓ基类?br />[15] 在其他领域中的分cL式未必适合作ؓ应用中的l承模型的分cL式?br />[16] Z行ؓ和不变式设计cdơ结构?br />[17] 考虑用例?br />[18] 考虑用CRC卡?br />[19] 用现存系l作为模型、灵感的源泉和出发点?br />[20] 意识到视觉图形工E的重要性?br />[21] 在原型成担时抛弃它?br />[22] 为变化而设计,注意力集中到灵zL、可扩展性、可UL性和重用?br />[23] 注意力集中到组件设计?br />[24] 让每个界面代表在一个抽象层ơ中的一个概c?br />[25] 面向变化q行设计Q以求得E_性?br />[26] 通过广泛频J用的界面做得最、最一般和抽象来设计E_?br />[27] 保持可能小Q不为“特D需要”增加新特征?br />[28] 总考虑cȝ其他表示方式。如果不可能有其他方式,q个cd能就没有代表某个清晰的概c?br />[29] 反复评审、精化设计和实现?br />[30] 采用那些能用于调试,用于分析问题、设计和实现的最好工兗?br />[31] 早、尽可能频繁地进行试验、分析和试?br />[32] 不要忘记效率?br />[33] 保持某种适合目规模的规范性水q?br />[34] 保证有h负责目的整体设计?br />[35] 为可重用lg做文档、推介和提供支持?br />[36] 目标与l节一起写q文档里?br />[37] ؓ新开发者提供的教许材料作ؓ文档的一部分?br />[38] 鼓励设计、库和类的重用,q给予回报?/p>
W?4?设计和编E?/p>
[1] 应该向数据抽象和面向对象设计的方向发展?br />[2] Q仅仅)Ҏ需要去使用C++的特征和技术?br />[3] 设计应与~程风格怺匚w?br />[4] 类/概念作ؓ设计中最基本的关注点Q而不是功?处理?br />[5] 用类表示概念?br />[6] 用承(仅仅Q表C概念间的层ơ结构关pR?br />[7] 利用应用层静态类型的方式l出有关界面的更强的保证?br />[8] 使用E序生成器和直接界面操作工具d成定义良好的工作?br />[9] 不要M用那些与M通用E序设计语言之间都没有清晰界面的E序生成器或者直接界面操作工兗?br />[10] 保存不同层次的抽象相互分R?br />[11] xlg设计?br />[12] 保证虚函数有定义良好的意义,每个覆盖函数都实现预期行为?br />[13] 公用界面表示的是“是一个”关pR?br />[14] 成员表示的是“有一个”关pR?br />[15] 在表C简单包Ҏ最好用直接成员Q不用指向单独分配的对象的指针?br />[16] 设法保证使用依赖关系为易理解的,可能不出现循环Q而且最?br />[17] 对于所有的c,定义好不变式?br />[18] 昑ּ地将前条件、后条g和其他断a表述为断aQ可能用Assert()Q?br />[19] 定义的界面应该只暴露初尽可能的信息?br />[20] 可能减一个界面对其他界面的依赖性?br />[21] 保持界面为强cd的?br />[22] 利用应用层的cd来表q界面?br />[23] 界面表q得使请求可以传递给q程得服务器?br />[24] 避免肥大的界面?br />[25] 可能地使用private数据和成员函数?br />[26] 用protected/private区分开zcȝ设计者与一般用户间的不同需要?br />[27] 使用模板d通用型程序设计?br />[28] 使用模板d法{略的参数化?br />[29] 如果需要在~译时做cd解析Q情使用模板?br />[30] 如果需要在q行时做cd解析Q请使用层次l构?/p>
W?5?cȝ作用
[1] 应该对一个类的用方式做出有意识的决{(作ؓ设计师或者作为用P?br />[2] 应注意到涉及不同U类的类之间的权衡问题?br />[3] 用具体类型去表示单的独立概念?br />[4] 用具体类型去表示那些最x果及其关键的概念?br />[5] 不要从具体类z?br />[6] 用抽象类去表C那些对象的表示可能变化的界面?br />[7] 用抽象类去表C那些可能出现多U对象表C共存情늚界面?br />[8] 用抽象类去表C现存类型的新界面?br />[9] 当类似概念共享许多实现细节时Q应该用结点类?br />[10] 用结点类去逐步扩充一个实现?br />[11] 用运行时cd识别从对象获取界面?br />[12] 用类去表C具有与之关联的状态信息的动作?br />[13] 用类去表C需要存储、传递或者gq执行的动作?br />[14] 利用界面cd为某U新的用法而调整一个类Q不修改q个c)?
[15] 利用界面cd加检查?br />[16] 利用句柄去避免直接用指针和引用?br />[17] 利用句柄ȝ理共享的表示?br />[18] 在那些能预先定义控制l构的应用领域中使用应用框架?/p>