??xml version="1.0" encoding="utf-8" standalone="yes"?> { q个规则同样适用于类的成员的布局? }
Z让编译器产生更好的代?比如说?DNow! 或SSE指o的代?Q必ȝ定Q点型变量和表辑ּ?float 型的。要特别注意的是Q以 "QF"Q??"Qf"Q?为后~Q比如:3.14fQ的点帔R才是 float 型,否则默认?double 型。ؓ了避?float 型参数自动{化ؓ doubleQ请在函数声明时使用 float?
2.使用32位的数据cd
~译器有很多U,但它们都包含的典型的32位类型是QintQsignedQsigned intQunsignedQunsigned intQlongQsigned longQlong intQsigned long intQunsigned longQunsigned long int。尽量?2位的数据cdQ因为它们比16位的数据甚至8位的数据更有效率?
3.明智使用有符h型变?
在很多情况下Q你需要考虑整型变量是有W号q是无符L型的。比如,保存一个h的体重数据时不可能出现负敎ͼ所以不需要用有W号cd。但是,如果是要保存温度数据Q就必须使用到有W号的变量?
在许多地方,考虑是否使用有符L变量是必要的。在一些情况下Q有W号的运比较快Q但在一些情况下却相反?
比如Q整型到点转化Ӟ使用大于16位的有符h型比较快。因为x86构架中提供了从有W号整型转化到Q点型的指令,但没有提供从无符h型{化到点的指令。看看编译器产生的汇~代码:
不好的代码:
~译? ~译?
double xQ mov [foo + 4], 0
unsigned int iQ mov eax, i
x = iQ mov [foo], eax
flid qword ptr [foo]
fstp qword ptr [x]
上面的代码比较慢。不仅因为指令数目比较多Q而且׃指o不能配对造成的FLID指o被gq执行。最好用以下代码代替Q?
推荐的代码:
~译前 编译后
double xQ fild dword ptr
int iQ fstp qword ptr [x]
x = iQ?
在整数运中计算商和余数Ӟ使用无符L型比较快。以下这D典型的代码是编译器产生?2位整型数除以4的代码:
不好的代码?
~译? ~译?
int iQ mov eax, i
i = i / 4Q? cdq
and edx, 3
add eax, edx
sar eax, 2
mov i, eax
推荐的代?br />~译? ~译?
unsigned int iQ? shr i, 2
i = i / 4Q?
ȝQ?br /> 无符L型用于:除法和余?循环计数,数组下标
有符L型用于:整型到Q点的转化
4.while VS. for
在编E中Q我们常帔R要用到无限@环,常用的两U方法是while (1) ?for (Q;)。这两种Ҏ效果完全一P但那一U更好呢Q然我们看看它们~译后的代码Q?
~译? ~译?
while (1)Q? mov eax,1
test eax,eax
je foo+23h
jmp foo+18h
~译? ~译后?
for (Q;)Q? jmp foo+23h
一目了Ӟfor (Q;)指o,不占用寄存器Q而且没有判断跌{Q比while (1)好?
5.使用数组型代替指针型
使用指针会ɾ~译器很难优化它。因为缺乏有效的指针代码优化的方法,~译器L假设指针可以讉K内存的Q意地方,包括分配l其他变量的储存I间。所以ؓ了编译器产生优化得更好的代码Q要避免在不必要的地方用指针。一个典型的例子是访问存攑֜数组中的数据。C++ 允许使用操作W?[] 或指针来讉K数组Q用数l型代码会让优化器减生不安全代码的可能性。比如,x[0] 和x[2] 不可能是同一个内存地址Q但 *p ?*q 可能。强烈徏议用数l型Q因样可能会有意料之外的性能提升?
不好的代?br />typedef struct
{
float x,y,z,wQ?br />} VERTEXQ?br />typedef struct
float m[4][4]Q?br />} MATRIXQ?br />void XForm(float* res, const float* v, const float* m, int nNumVerts)
{
float dpQ?br /> int iQ?br /> const VERTEX* vv = (VERTEX *)vQ?br /> for (i = 0Q?i <Q?nNumVertsQ?i++)
{
dp = vv->Qx * *m ++Q?br /> dp += vv->Qy * *m ++Q?br /> dp += vv->Qz * *m ++Q?br /> dp += vv->Qw * *m ++Q?br /> *res ++ = dpQ // 写入转换了的 x
dp = vv->Qx * *m ++Q?br /> dp += vv->Qy * *m ++Q?br /> dp += vv->Qz * *m ++Q?br /> dp += vv->Qw * *m ++Q?br /> *res ++ = dpQ // 写入转换了的 y
dp = vv->Qx * *m ++Q?br /> dp += vv->Qy * *m ++Q?br /> dp += vv->Qz * *m ++Q?br /> dp += vv->Qw * *m ++Q?br /> *res ++ = dpQ // 写入转换了的 z
dp = vv->Qx * *m ++Q?br /> dp += vv->Qy * *m ++Q?br /> dp += vv->Qz * *m ++Q?br /> dp += vv->Qw * *m ++Q?br /> *res ++ = dpQ // 写入转换了的 w
vv ++Q // 下一个矢?br /> m -= 16Q?br /> }
}
推荐的代?
typedef struct
{
float x,y,z,wQ?br />} VERTEXQ?br />typedef struct
{
float m[4][4]Q?br />} MATRIXQ?br />void XForm (float* res, const float* v, const float* m, int nNumVerts)
{
int iQ?br /> const VERTEX* vv = (VERTEX*)vQ?br /> const MATRIX* mm = (MATRIX*)mQ?br /> VERTEX* rr = (VERTEX*)resQ?br /> for (i = 0Q?i <Q?nNumVertsQ?i++)
{
rr->Qx = vv->Qx * mm->Qm[0][0] + vv->Qy * mm->Qm[0][1]
+ vv->Qz * mm->Qm[0][2] + vv->Qw * mm->Qm[0][3]Q?br /> rr->Qy = vv->Qx * mm->Qm[1][0] + vv->Qy * mm->Qm[1][1]
+ vv->Qz * mm->Qm[1][2] + vv->Qw * mm->Qm[1][3]Q?br /> rr->Qz = vv->Qx * mm->Qm[2][0] + vv->Qy * mm->Qm[2][1]
+ vv->Qz * mm->Qm[2][2] + vv->Qw * mm->Qm[2][3]Q?br /> rr->Qw = vv->Qx * mm->Qm[3][0] + vv->Qy * mm->Qm[3][1]
+ vv->Qz * mm->Qm[3][2] + vv->Qw * mm->Qm[3][3]Q?br /> }
}
注意: 源代码的转化是与~译器的代码发生器相l合的。从源代码层ơ很难控制生的机器码。依靠编译器和特D的源代码,有可能指针型代码~译成的机器码比同等条g下的数组型代码运行速度更快。明智的做法是在源代码{化后查性能是否真正提高了,再选择使用指针型还是数l型?
6.充分分解的循环
要充分利用CPU的指令缓存,p充分分解的循环。特别是当@环体本n很小的时候,分解循环可以提高性能。BTW:很多~译器ƈ不能自动分解循环?
不好的代?推荐的代?
// 3D转化Q把矢量 V ?4x4 矩阵 M 怹
for (i = 0Q?i <Q?4Q?i ++)
{
r = 0Q?br /> for (j = 0Q?j <Q?4Q?j ++)
{
r += M[j]*V[j]Q?br /> }
}
r[0] = M[0][0]*V[0] + M[1][0]*V[1] + M[2][0]*V[2] + M[3][0]*V[3]Q?br />r[1] = M[0][1]*V[0] + M[1][1]*V[1] + M[2][1]*V[2] + M[3][1]*V[3]Q?br />r[2] = M[0][2]*V[0] + M[1][2]*V[1] + M[2][2]*V[2] + M[3][2]*V[3]Q?br />r[3] = M[0][3]*V[0] + M[1][3]*V[1] + M[2][3]*V[2] + M[3][3]*v[3]Q?
7.避免没有必要的读写依?
当数据保存到内存时存在读写依赖,x据必d正确写入后才能再ơ读取。虽然AMD Athlon{CPU有加速读写依赖gq的gQ允许在要保存的数据被写入内存前d出来Q但是,如果避免了读写依赖ƈ把数据保存在内部寄存器中Q速度会更快。在一D很长的又互怾赖的代码链中Q避免读写依赖显得尤光要。如果读写依赖发生在操作数组Ӟ许多~译器不能自动优化代码以避免d依赖。所以推荐程序员手动L除读写依赖,举例来说Q引q一个可以保存在寄存器中的时变量。这样可以有很大的性能提升。下面一D代码是一个例子:
不好的代?br />float x[VECLEN], y[VECLEN], z[VECLEN]Q?br />......
for (unsigned int k = 1Q?k <Q?VECLENQ?k ++)
{
x[k] = x[k-1] + y[k]Q?br />}
for (k = 1Q?k <Q?VECLENQ?k++)
{
x[k] = z[k] * (y[k] - x[k-1])Q?br />}
推荐的代?
float x[VECLEN], y[VECLEN], z[VECLEN]Q?br />......
float t(x[0])Q?br />for (unsigned int k = 1Q?k <Q?VECLENQ?k ++)
{
t = t + y[k]Q?br /> x[k] = tQ?br />}
t = x[0]Q?br />for (k = 1Q?k <Q?VECLENQ?k ++)
{
t = z[k] * (y[k] - t)Q?br /> x[k] = tQ?br />}
8.Switch 的用?
Switch 可能转化成多U不同算法的代码。其中最常见的是跌{表和比较?树。推荐对case的g照发生的可能性进行排序,把最有可能的攑֜W一个,当switch用比较链的方式{化时Q这样可以提高性能。此外,在case中推荐用小的连l的整数Q因为在q种情况下,所有的~译器都可以把switch 转化成蟩转表?
不好的代?br />int days_in_month, short_months, normal_months, long_monthsQ?br />......
switch (days_in_month)
{
case 28:
case 29:
short_months ++Q?br /> breakQ?br /> case 30:
normal_months ++Q?br /> breakQ?br /> case 31:
long_months ++Q?br /> breakQ?br /> default:
cout <Q?lt;Q?"Qmonth has fewer than 28 or more than 31 days"Q?<Q?lt;Q?endlQ?br /> breakQ?br />}
推荐的代?
int days_in_month, short_months, normal_months, long_monthsQ?br />......
switch (days_in_month)
{
case 31:
long_months ++Q?br /> breakQ?br /> case 30:
normal_months ++Q?br /> breakQ?br /> case 28:
case 29:
short_months ++Q?
breakQ?br /> default:
cout <Q?lt;Q?"Qmonth has fewer than 28 or more than 31 days"Q?<Q?lt;Q?endlQ?br /> breakQ?br />}
9.所有函数都应该有原型定?
一般来_所有函数都应该有原型定义。原型定义可以传辄~译器更多的可能用于优化的信息?
可能用常?const)。C++ 标准规定Q如果一个const声明的对象的地址不被获取Q允许编译器不对它分配储存空间。这样可以代码更有效率Q而且可以生成更好的代码?
10.提升循环的性能
要提升@环的性能Q减多余的帔R计算非常有用Q比如,不随循环变化的计)?
不好的代?在for()中包含不变的if()) 推荐的代?
for( i ... )
{
if( CONSTANT0 )
{
DoWork0( i )Q?// 假设q里不改变CONSTANT0的?br /> }
else
{
DoWork1( i )Q?// 假设q里不改变CONSTANT0的?br /> }
}
if( CONSTANT0 )
{
for( i ... )
{
DoWork0( i )Q?br /> }
}
else
{
for( i ... )
{
DoWork1( i )Q?br /> }
}
如果已经知道if()的|q样可以避免重复计算。虽然不好的代码中的分支可以单地预测Q但是由于推荐的代码在进入@环前分支已经定Q就可以减少对分支预的依赖? 把本地函数声明ؓ静态的(static)
如果一个函数在实现它的文g外未被用的话,把它声明为静态的(static)以强制用内部连接。否则,默认的情况下会把函数定义为外部连接。这样可能会影响某些~译器的优化——比如,自动内联?
11.考虑动态内存分?
动态内存分配(C++中的"Qnew"Q)可能L为长的基本类型(四字寚wQ返回一个已l对齐的指针。但是如果不能保证对齐,使用以下代码来实现四字对齐。这D代码假设指针可以映到 long 型?
例子
double* p = (double*)new BYTE[sizeof(double) * number_of_doubles+7L]Q?br /> double* np = (double*)((long(p) + 7L) &Q??L)Q?
现在Q你可以使用 np 代替 p 来访问数据。注意:释放储存I间时仍然应该用delete p?
12.使用昑ּ的ƈ行代?
可能把长的有依赖的代码铑ֈ解成几个可以在流水线执行单元中ƈ行执行的没有依赖的代码链。因为QҎ作有很长的潜伏期Q所以不它被映成 x87 ?3DNow! 指oQ这都很重要。很多高U语aQ包括C++Qƈ不对产生的Q点表辑ּ重新排序Q因为那是一个相当复杂的q程。需要注意的是,重排序的代码和原来的代码在代C一致ƈ不等价于计算l果一_因ؓ点操作~Z_度。在一些情况下Q这些优化可能导致意料之外的l果。幸q的是,在大部分情况下,最后结果可能只有最不重要的位(x低位Q是错误的?
不好的代?br />double a[100], sumQ?br />int iQ?br />sum = 0.0fQ?br />for (i=0Q?i<Q?00Q?i++)
sum += aQ?
推荐的代?
double a[100], sum1, sum2, sum3, sum4, sumQ?br />int iQ?br />sum1 = sum2 = sum3 = sum4 = 0.0Q?br />for (i = 0Q?i <Q?100Q?i += 4)
{
sum1 += aQ?br /> sum2 += a[i+1]Q?br /> sum3 += a[i+2]Q?br /> sum4 += a[i+3]Q?br />}
sum = (sum4+sum3)+(sum1+sum2)Q?
要注意的是:使用4 路分解是因ؓq样使用?阶段水UQ点加法,点加法的每一个阶D占用一个时钟周期,保证了最大的资源利用率?
13.提出公共子表辑ּ
在某些情况下QC++~译器不能从点表达式中提出公共的子表达式,因ؓq意味着相当于对表达式重新排序。需要特别指出的是,~译器在提取公共子表辑ּ前不能按照代数的{h关系重新安排表达式。这ӞE序员要手动地提出公q子表辑ּQ在VC.net里有一“全局优化”选项可以完成此工作,但效果就不得而知了)?
推荐的代?
float a, b, c, d, e, fQ?br />...
e = b * c / dQ?br />f = b / d * aQ?br />float a, b, c, d, e, fQ?br />...
const float t(b / d)Q?br />e = c * tQ?br />f = a * tQ?
推荐的代?
float a, b, c, e, fQ?br />...
e = a / cQ?br />f = b / cQ?br />float a, b, c, e, fQ?br />...
const float t(1.0f / c)Q?br />e = a * tQ?br />f = b * tQ?
14.l构体成员的布局
很多~译器有“ɾl构体字Q双字或四字寚w”的选项。但是,q是需要改善结构体成员的对齐,有些~译器可能分配给l构体成员空间的序与他们声明的不同。但是,有些~译器ƈ不提供这些功能,或者效果不好。所以,要在付出最代L情况下实现最好的l构体和l构体成员对齐,采取q些ҎQ?
A按类型长度排?
把结构体的成员按照它们的cd长度排序Q声明成员时把长的类型放在短的前面?
把结构体填充成最长类型长度的整倍数
把结构体填充成最长类型长度的整倍数。照q样Q如果结构体的第一个成员对齐了Q所有整个结构体自然也就寚w了。下面的例子演示了如何对l构体成员进行重新排序:
不好的代码,普通顺?推荐的代码,新的序q手动填充了几个字节
struct
{
char a[5]Q?br /> long kQ?br /> double xQ?br />} bazQ?br />struct
{
double xQ?br /> long kQ?br /> char a[5]Q?br />char pad[7]Q?br />} bazQ?
B按数据类型的长度排序本地变量
当编译器分配l本地变量空间时Q它们的序和它们在源代码中声明的顺序一P和上一条规则一P应该把长的变量放在短的变量前面。如果第一个变量对齐了Q其它变量就会连l的存放Q而且不用填充字节自然׃寚w。有些编译器在分配变量时不会自动改变变量序Q有些编译器不能产生4字节寚w的栈Q所?字节可能不对齐。下面这个例子演CZ本地变量声明的重新排序:
不好的代码,普通顺?推荐的代码,改进的顺?
short ga, gu, giQ?br />long foo, barQ?br />double x, y, z[3]Q?br />char a, bQ?br />float bazQ?br />double z[3]Q?br />double x, yQ?br />long foo, barQ?br />float bazQ?br />short ga, gu, giQ?
14.避免不必要的整数除法
整数除法是整数运中最慢的Q所以应该尽可能避免。一U可能减整数除法的地方是连除,q里除法可以׃法代ѝ这个替换的副作用是有可能在乘U时会溢出,所以只能在一定范围的除法中用?
不好的代?推荐的代?
int i, j, k, mQ?br />m = i / j / kQ?br />int i, j, k, mQ?br />m = i / (j * k)Q?
15.把频J用的指针型参数拷贝到本地变量
避免在函C频繁使用指针型参数指向的倹{因为编译器不知道指针之间是否存在冲H,所以指针型参数往往不能被编译器优化。这h数据不能被存攑֜寄存器中Q而且明显地占用了内存带宽。注意,很多~译器有“假设不冲突”优化开养I在VC里必L动添加编译器命o?Oa?OwQ,q允许编译器假设两个不同的指针L有不同的内容Q这样就不用把指针型参数保存到本地变量。否则,请在函数一开始把指针指向的数据保存到本地变量。如果需要的话,在函数结束前拯回去?
不好的代?
// 假设 q != r
void isqrt(unsigned long a, unsigned long* q, unsigned long* r)
{
*q = aQ?br /> if (a >Q?0)
{
while (*q >Q?(*r = a / *q))
{
*q = (*q + *r) >Q?gt;Q?1Q?br /> }
}
*r = a - *q * *qQ?br />}
推荐的代?br />// 假设 q != r
void isqrt(unsigned long a, unsigned long* q, unsigned long* r)
{
unsigned long qq, rrQ?br /> qq = aQ?br /> if (a >Q?0)
{
while (qq >Q?(rr = a / qq))
{
qq = (qq + rr) >Q?gt;Q?1Q?br /> }
}
rr = a - qq * qqQ?br /> *q = qqQ?br /> *r = rrQ?br />}
16.赋g初始?br />先看看以下代码:
class CInt
{
int m_iQ?
public:
CInt(int a = 0):m_i(a) { cout <Q?lt;Q?"QCInt"Q?<Q?lt;Q?endlQ?}
~CInt() { cout <Q?lt;Q?"Q~CInt"Q?<Q?lt;Q?endlQ?}
CInt operator + (const CInt&Q?a) { return CInt(m_i + a.GetInt())Q?}
void SetInt(const int i) { m_i = iQ?}
int GetInt() const { return m_iQ?}
}Q?br /> 不好的代?
void main()
{
CInt a, b, cQ?br /> a.SetInt(1)Q?br /> b.SetInt(2)Q?br /> c = a + bQ?br />}
推荐的代?br />void main()
{
CInt a(1), b(2)Q?br /> CInt c(a + b)Q?br />}
q两D代码所作的事都一P但那一个更好呢Q看看输出结果就会发玎ͼ不好的代码输Z四个"QCInt"Q和四个"Q~CInt"Q,而推荐的代码只输Z个。也是_W二个例子比W一个例子少生成一ơ时对象。Why? h意,W一个中的c用的是先声明再赋值的ҎQ第二个用的是初始化的方法,它们有本质的区别。第一个例子的"Qc = a + b"Q先生成一个时对象用来保存a + b的|再把该时对象用位拷贝的Ҏlc赋|然后临时对象被销毁。这个时对象就是那个多出来的对象。第二个例子直接用拷贝构造函数的Ҏ对c初始化,不生时对象。所以,量在需要用一个对象时才声明,q用初始化的Ҏ赋初倹{?
17.量使用成员初始化列?
在初始化cȝ成员Ӟ量使用成员初始化列表而不是传l的赋值方式?
不好的代?
class CMyClass
{
string strNameQ?
public:
CMyClass(const string&Q?str)Q?br />}Q?
CMyClass::CMyClass(const string&Q?str)
{
strName = strQ?br />}
推荐的代?br />class CMyClass
{
string strNameQ?br /> int iQ?br />public:
CMyClass(const string&Q?str)Q?br />}Q?
CMyClass::CMyClass(const string&Qstr)
:strName(str)
{
不好的例子用的是赋值的方式。这PstrName会先被徏立(调用了string的默认构造函敎ͼQ再由参数str赋倹{而推荐的例子用的是成员初始化列表QstrName直接构造ؓstrQ少调用一ơ默认构造函敎ͼq少了一些安全隐患?/p>
]]>
无数ơ听到“我要开始学习C++!”的呐喊Q无数次听到“C++太复杂了Q我真的学不会”的无奈。Stan Lippman先生曑֜《C++ Primer》一书中指出“C++是最为难学的高E序设计语言之一”,Z常将“之一”去掉以表达自己对C++的敬畏。诚ӞC++E序设计语言对于学习者的有很多难以逾越的`沟,体系l构的庞大,应接不暇q不断扩充的Ҏ……除此之外,参考资料之多与冗杂使它的学习者望而却步,Ʋ求深入者苦不堪a。希望这一份不完全导引能够成ؓ您C++学习之\上的引\灯?/p>
撰写本文的初衷ƈ不打带领大家体验古老的C++历史Q如果你想了解C++的历史与其前期发展中诸多技术的演变Q你应当d考Bjarne的《The Design and Evolution of C++》。当然也不打给大家一个无所不包的宝典(q不想Q其一是因水^有限Q其二无奈C++之博大精深)Q所l出的仅仅是一些我们认为对于想学习C++的广大读者来说最重要q且触手可及的开发与学习资源?/p>
本文介绍q分析了一些编译器Q开发环境,库,量的书c以及参考网站,q且可能尝试着l出一个利用这些资源的导引Q望对如同我们一L初学者能够有所裨益?/p>
2Q编译器
在C++之外的Q何语a中,~译器都从来没有受到q如此之重视。因为C++是一门相当复杂的语言Q所以编译器也难于构建。直到最q我们才开始能够用上完全W合C++标准的编译器Q哦Q你可能会责怪那些编译器厂商不能早的提供符合标准的~译器,q只能怪他们各自维pȝ自n的一套别Z愿接受的标准Q。什么?你说q无关紧要?哦,不,你所需要的是和标准化C++高度兼容的编译环境。长q来?br />Q只有这L~译器对C++开发h员来说才是最有意义的工具Q尤其是对于E序设计语言的学习者。一x让代码具备可移植性,q让一门语a及其库的应用更ؓq泛。嗯Q是的,我们q里只打介l一些公认的优秀~译器?/p>
2.1 Borland C++
q个是Borland C++ Builder和Borland C++ Builder Xq两U开发环境的后台~译器。(哦,我之所以将之分ZU开发环境你应当能明白ؓ什么,正如Delphi7到Delphi8的{变,是革命性的两代。)Borland C++p牌开发工具厂商Borland們֊打造。该公司的编译器素以速度快,I间效率高著UͼBorland C++ pd~译器秉承了q个传统Q属于非怼质的~译器。标准化斚w早在5.5版本的编译器中对标准化C++的兼容就辑ֈ?2.73%。目前最新版本是Borland C++ Builder X中的6.0版本Q官方称100%W合ANSI/ISO的C++标准以及C99标准。嗯…这正是我前面所指的“完全符合C++标准的编译器”?/p>
2.2 Visual C++
q个正是我们熟知的Visual Studio ?Visual Studio.net 2002, 2003以及2005 Whidbey中带的C++~译器。由Microsoft公司研制。在Visual Studio 6.0中,因ؓ~译器有太多地方不能与后来出现的C++标准相吻合而饱受批评(x你在使用STL的时候编译时报出的那些o人厌恶的error和warning吧)。VC++6.0Ҏ准化C+
+的兼容只?3.43%。但是随着C++~译器设计大师Stanley Lippman以及诸多C++C达h的加盟,在Visual Studio.NET 2003中,Visual C++~译器已l成Z个非常成熟可*的C++~译器了。Dr.Dobb's Journal的评显CVisual C++7.1Ҏ准C++的兼Ҏ高?8.22%Q一度成为CBX之前兼容性最好的~译器。结合强大的Visual Studio.NET开发环境,是一个非怸错的选择。至于Whidbey时代的Visual C++,g微Y所最x的是C++/CLI……我们不惌论微软下一代的C++~译器对标准化兼容如何,但他实来适合.NET (其实你和我的感觉可能是一LQ微软不应当把标准C++q块肥肉丢给Borland,然而微软可能ƈ不这栯??/p>
2.3 GNU C++
著名的开源C++~译器。是cUnix操作pȝ下编写C++E序的首选。特Ҏ有非常好的移植性,你可以在非常q泛的^C使用它,同时也是~写跨^収ͼ嵌入式程序很好的选择。另外在W合标准q个斚w一直都非常好,GCC3.3大概能够辑ֈ96.15%。但是由于其跨^台的Ҏ,在代码尺寔R度{优化上略微差一炏V?/p>
ZGNU C++的编译器有很多,比如Q?/p>
(1) Mingw
GCC的一个Windows的移植版本(Dev-C++的后収ͼ
(2) Cygwin
http://sources.redhat.com/cygwin/
GCC的另外一个WindowsUL版本是Cygwin的一部分QCygwin是Windows下的一个Unix仿真环境。严格的说是模拟GNU的环境,q也是"Gnu's Not Unix"要表辄意思,噢,扯远了,qƈ不是我们在这里关心的实质内容?/p>
(3) Djgpp
q是GCC的DOSUL版本?/p>
(4) RSXNT
http://www.mathematik.uni-bielefeld.de/~rainer/
q是GCC的DOS和WindowsUL版本?/p>
(5) Intel C++
著名CPU刉厂商Intel出品的编译器QSpecial Design for Intel x86Q对于Intel x86l构的CPUl过特别的优化。在有些应用情况下,特别是数D等高性能应用Q仅仅采用Intel的编译器~译p大幅度的提高性能?/p>
(6) Digital Mars C++
|络上提供免费下载,Zortech/Symantec C++的承者,其前w在当年惨烈的C++四国战中也是主角之一?/p>
3Q开发环?/p>
开发环境对于程序员的作用不a而喻。选择自己朝夕相处的环境也不是Ҏ的事情,特别是在IDE如此丰富的情况下。下面就是我们推荐的一些常见的C++开发环境,q没有包括一些小型的Q罕见的IDE。其中Q何一N是功能丰富,可以用作日常开发用的。对于不同层面的开发者,请参见内文关于适用对象的描q?/p>
3.1 Visual Studio 6.0
q个虽然是Microsoft公司的老版本的开发环境,但是鉴于其后l版本VisualStudio.NET的庞大nw,以及初学者ƈ不那么高的功能要求,所以推荐这个开发环境给C++的初学者,供其学习C++的最基本的部分,比如C的那部分子集Q当然你别指望他能够支持最新的C99标准。在日常的开发中Q仍然有很多公司使用q个l典E_的环境,比如W者就看曾亲见有些公司其~译器替换ؓGCC做手机开发之用?/p>
3.2 Visual Studio.NET 2003
作ؓMicrosoft公司官方正式发布的最新版本开发环境,其中有太多激动h心的功能。结合其最新的C++~译器。对于机器配|比较好的开发h员来_使用q个开发环境将能满_大部分的要求。这里不打算单独说Visual Studio Whidbey,虽然Visual Studio .NET 2005 - WhidbeyC预览版已l推出,但暂不是很稳定,读者可以亲w去体验?/p>
3.3 Borland C++ Builder 6
q个q不是Borland的C++开发环境的最新版本。选择它的原因是它不是用Java写的IDEQ速度比较快。它有一个很完善的GUIH体设计器,和Delphiq一个VCL。由于这些特点,比较适合初学者上手。但是由于其GUI的中心位|,可能不利于对于C++语言的学习。而且其ؓ了支持VCLq个Object Pascal写的库也对C++q行了一些私有的扩充。得h们有一个不得不接受的事实:“Borland C++ Builder 6的高?br />几乎都是Delphi高手”?/p>
3.4 Borland C++ Builder X
正如前文所qͼ虽然版本号上和前面那个IDE非常相象Q但是其实它们是完全不同的两个集成开发环境。C++Builder更多的是一个和Delphi同步的C++版本的开发环境,C++BuilderX则是完全从C++的角度思考得出的一个功能丰富的IDE。其最大的特点是跨q_Q跨~译器,多种Framework的集成,q且有一个WxWindows为基的GUI设计器。尤其是采用了纯C++来重写了整个Framework,摒弃了以前o人无奈的版本。对于C++的开发来_从编译器Q到库,到功能集成都是非常理想的。可以预见,Borland C++ Builder X 2.0很值得C++爱好者期待。唯一令h隑֠之处是作Z个C++的开发工P其IDE是用Java写的Q在配置不够理想的机器上h重考虑再安装?/p>
3.5 Emacs + GCC
前面讲的大部分是Windows环境下的集成开发环境。Linux上的开发者更們于用Emacs来编辑C++的文Ӟ用Makefile来命令GCC做编译。虽然看上去比较松散Q但是这些东西综合v来还是一个开0发环境。如果你能够娴熟的用这L环境写程序,你的水^应该_指导我们来写q篇陋文了?/p>
3.6 Dev C++
GCC是一个很好的~译器。在Windows上的C++~译器一直和标准有着一D距ȝ时候,GCC是一个让Windows下开发者流口水的编译器。Dev-C++是能够让GCC跑在Windows下的工具Q作为集成开发环境,q提供了同专业IDE相媲的语法高亮Q代码提C,调试{功能。由于用Delphi开发,占用内存,速度很快Q比较适合轻量U的学习和用?/p>
3.7 Eclipse + CDT
Eclipse可是q来大名鼎鼎的开发工兗最C期的Jolt大奖颁l了q个杰出的神物。说其神奇是因ؓQ它本n是用Java写的Q但是拥有比一般Java写的E序快得多的速度。而且因ؓ其基于插件组装一切的原则Q得能够有CDTq样的插件把Eclipse变成一个C/C++的开发环境。如果你一直用Eclipse写Java的程序,不妨用它体验一下C++开发的乐趣?/p>
--------------------------------------------------------------------------------
4Q工?/p>
C++的辅助工L多,我们分门别类的ؓ大家作介l:
4.1 文档c?/p>
(1) Doxygen
Doxygen是一U适合C风格语言Q如C++、C、IDL、Java甚至包括C#和PHPQ的、开放源码的、基于命令行的文档生器?/p>
(2) C++2HTML
参考站点:http://www.bedaux.net/cpp2html/
把C++代码变成语法高亮的HTML
(3) CodeColorizer
参考站点:http://www.chami.com/colorizer/
它能把好几种语言的源代码着色ؓHTML
(4) Doc-O-Matic
参考站点:http://www.doc-o-matic.com/
Doc-O_MaticZ的C/C++QC++.netQDelphi/Pascal, VB.NETQC#和JavaE序或者组件生准的文档。Doc-O-Matic使用源代码中的符号和注释以及外部的文档文件创Z行的文档样式一致的文档?/p>
(5) DocVizor
参考站点:http://www.ucancode.net/Products/DocBuilder/Features.htm
DocVizor满了面向对象Y件开发者的基本要求——它让我们能够看到C++工程中的cdơ结构。DocVizor快速地产生完整可供打印的类层次l构图,包括从第三方库中来的那些c,除此之外DocVizorq能从类信息中生HTML文g?/p>
(6) SourcePublisher C++
参考站点:http://www.scitools.com/sourcepublisher_c.html
l源代码产生提供快速直观的HTML报表Q包括代码,cdơ结构,调用和被调用树,包含和被包含树。支持多U操作系l?/p>
(7) Understand
参考站点:http://www.scitools.com/ucpp.html
分析M规模的C或者C++工程Q帮助我们更好的理解以及~写文档?/p>
4.2 代码c?/p>
(1) CC-Rider
CC-Rider是用于C/C++E序强大的代码可视化工具Q通过交互式浏览、编辑及自动文g来促q程序的l持和发展?/p>
(2) CodeInspect
一U新的C/C++代码分析工具。它查我们的源代码找出非标准的,可能的,以及普通的错误代码?/p>
(3) CodeWizard
先进的C/C++源代码分析工P使用过500个编码规范自动化地标明危险的Q但是编译器不能查到的代码结构?/p>
(4) C++ Validation Test Suites
参考站点:http://www.plumhall.com/suites.html
一l用于测试编译器和库对于标准dE度的代码库?/p>
(5) CppRefactory
参考站点:http://cpptool.sourceforge.net/
CPPRefactory是一个得开发者能够重构他们的C++代码的程序。目的是使得C++代码的重构能够尽可能的有效率和简单?/p>
(6) Lzz
参考站点:http://www.lazycplusplus.com/
Lzz是一个自动化许多C++~程中的体力zȝ工具。它能够节省我们许多事gq且使得~码更加有乐。给Zpd的声明,Lzz会给我们创徏头文件和源文件?/p>
(7) QA C++ Generation 2000
参考站点:http://www.programmingresearch.com/solutions/qacpp.htm
它关注面向对象的C++源代码,Ҏ关于设计Q效率,?性,可维护性的部分提出警告信息?/p>
(8) s-mail project - Java to C++DOL
参考站点:http://sadlocha.strefa.pl/s-mail/ja2dol.html
把Java源代码翻译ؓ相应的C++源代码的命o行工兗?/p>
(9) SNIP from Cleanscape Software International
参考站点:http://www.cleanscape.net/stdprod/snip/index.html
一个填q编码和设计之间沟壑的易于用的C++开发工P节省大量~辑和调试的事gQ它q得开发者能够指定设计模式作为对象模型,自动从对象模型中产生C++的类?/p>
(10) SourceStyler C++
参考站点:http://www.ochresoftware.com/
对C/C++源代码提供完整的格式化和排版控制的工兗提供多?5个的格式化选项以及完全支持ANSI C++?/p>
4.3 ~译c?/p>
(1) Compilercache
参考站点:http://www.erikyyy.de/compilercache/
Compilercache是一个对你的C和C++~译器的装脚本。每ơ我们进行编译,装脚本Q把~译的结果放入缓存,一旦编译相同的东西Q结果将从缓存中取出而不是再ơ编译?/p>
(2) Ccache
Ccache是一个编译器~存。它使用h像C/C++~译器的~存预处理器Q编译速度通常能提高普通编译过E的5~10倍?/p>
(3) Cmm (C++ with MultiMethods)
参考站点:http://www.op59.net/cmm/cmm-0.28/users.html
q是一UC++语言的扩展。读入Cmm源代码输出C++的源代码Q功能是对C++语言d了对multimethod的支持?/p>
(4) The Frost Project
Forst使得你能够在C++E序中像原生的C++Ҏ一样用multimethod以及虚函数参数。它是一个编译器的外壟?/p>
4.4 试和调试类
(1) CPPUnit
CppUnit 是个Z LGPL 的开源项目,最初版本移植自 JUnitQ是一个非怼U的开源测试框架。CppUnit ?JUnit 一样主要思想来源于极限编E。主要功能就是对单元试q行理Qƈ可进行自动化试?br />
(2) C++Test
C++ Test是一个单元测试工P它自动化了C和C++c,函数或者组件的试?/p>
(3) Cantata++
参考站点:http://www.iplbath.com/products/tools/pt400.shtml
设计的目的是Z满在合理的l济开销下用这个工具可以让开发工E师开展单元测试和集成试的需?
(4) Purify
参考站点:http://www-900.ibm.com/cn/software/rational/products/purif
yplus/index.shtml
IBM Rational PurifyPlus是一套完整的q行时分析工P旨在提高应用E序的可*性和性能。PurifyPlus内存错误和泄漏、应用程序性能描述、代码覆盖分析等功能l合在一个单一、完整的工具包中?/p>
(5) BoundsChecker
BoundsChecker是一个C++q行旉误检和调试工具。它通过在Visual Studio内自动化调试q程加速开发ƈ且羃短上市的周期。BoundsChecker提供清楚Q详l的E序错误分析Q许多是对C++独有的ƈ且在staticQstack和heap内存中检和诊断错误Q以及发现内存和资源的泄漏。
(6) Insure++
一个自动化的运行时E序试工具Q检查难以察觉的错误,如内存覆盖,内存泄漏Q内存分配错误,变量初始化错误,变量定义冲突Q指针错误,库错误,逻辑错误和算法错误等?/p>
(7) GlowCode
GlowCode包括内存泄漏查,code profilerQ函数调用跟t等功能。给C++开发者提供完整的错误诊断Q和q行时性能分析工具包?/p>
(8) Stack Spy
参考站点:http://www.imperioustech.com/
它能捕捉stack corruption, stack over run, stack overflow{有x的错误?/p>
------------------------------------------------------------------------
5Q库
在C++中,库的C是非帔R的。C++之父 Bjarne Stroustrup先生多次表示了设计库来扩充功能要好过设计更多的语法的a论。现实中QC++的库门类J多Q解决的问题也是极其q泛Q库从轻量到重量的都有。不都是让人眼界大开Q亦或是望而生叹的思维C。由于库的数量非常庞大,而且限于W者水qI其中很多q不了解。所以文中所提的一些库都是比较著名的大型库?/p>
5.1 标准?/p>
标准库中提供了C++E序的基本设施。虽然C++标准库随着C++标准折腾了许多年Q直到标准的出台才正式定型,但是在标准库的实C却很令hƣ慰得看到多U实玎ͼq且已被实践证明为有工业U别强度的佳作?/p>
(1) Dinkumware C++ Library
参考站点:http://www.dinkumware.com/
P.J. Plauger~写的高品质的标准库。P.J. Plauger博士是Dr. Dobb'sE序设计杰出奖的获得者。其~写的库长期被Microsoft采用Qƈ且最qBorland也取得了其OEM的licenseQ在其C/C++的品中采用Dinkumware的库?/p>
(2) RogueWave Standard C++ Library
参考站点:http://www.roguewave.com/
q个库在Borland C++ Builder的早期版本中曄被采用,后来被其他的库给替换了。笔者不推荐使用?/p>
(3) SGI STL
参考站点:http://www.roguewave.com/
SGI公司的C++标准模版库?/p>
(4) STLport
SGI STL库的跨^台可UL版本?/p>
5.2 “准”标准库 - Boost
国内镜像Q?a >http://www.c-view.org/tech/lib/boost/index.htm
Boost库是一个经q千锤百点{可UL、提供源代码的C++库,作ؓ标准库的后备Q是C++标准化进E的发动Z一?Boost库由C++标准委员会库工作l成员发P在C++C中媄响甚大,其成员已q?000人?Boost库ؓ我们带来了最新、最酗最实用的技术,是不折不扣的“准”标准库?/p>
Boost中比较有名气的有q么几个库:
Regex
正则表达式库
Spirit
LL parser frameworkQ用C++代码直接表达EBNF
Graph
囄件和法
Lambda
在调用的地方定义短小匿名的函数对象,很实用的functional功能
concept check
查泛型编E中的concept
Mpl
用模板实现的元编E框?/p>
Thread
可移植的C++多线E库
Python
把C++cd函数映射到Python之中
Pool
内存池管?/p>
smart_ptr
5个智能指针,学习指针必读Q一份不错的参考是来自CUJ的文章:
Smart Pointers in BoostQ哦Q这文章可以查刎ͼCUJ是提供在U浏览的。中文版见笔者在《Dr. Dobb's Journal软g研发杂志》第7辑上的译文?/p>
BoostM来说是实用h值很高,质量很高的库。ƈ且由于其对跨q_的强调,Ҏ准C++的强调,是编写^台无养ICC++的开发者必备的工具。但是Boost中也有很多是实验性质的东西,在实际的开发中实用需要}慎。ƈ且很多Boost中的库功能堪U对语言功能的扩展,其构造用精巧的手法Q不要N然的p旉研读。Boost另外一面,比如Graphq样的库则是h工业强度Q结构良好,非常值得研读的精品代码,q且也可以放心的在品代码中多多利用?/p>
5.3 GUI
在众多C++的库中,GUI部分的库是比较J荣Q也比较引h注目的。在实际开发中QGUI库的选择也是非常重要的一件事情,下面我们lD一下可选择的GUI库,各自的特点以及相兛_L支持?/p>
(1) MFC
大名鼎鼎的微软基cdQMicrosoft Foundation ClassQ。大凡学qVC++的h都应该知道这个库。虽然从技术角度讲QMFC是不大漂亮的Q但是它构徏于Windows API 之上Q能够ɽE序员的工作更容?~程效率高,减少了大量在建立 Windows E序时必ȝ写的代码Q同时它q提供了所有一?C++ ~程的优点,例如l承和封装。MFC ~写的程序在各个版本的Windows操作pȝ上是可移植的Q例如,在Windows 3.1下编写的代码可以很容易地UL?Windows NT ?Windows 95 上。但是在最q发展以及官Ҏ持上日渐势微?/p>
(2) QT
参考网站:http://www.trolltech.com/
Qt是Trolltech公司的一个多q_的C++囑Ş用户界面应用E序框架。它提供l应用程序开发者徏立艺术的图形用L面所需的所用功能。Qt是完全面向对象的很容易扩展,q且允许真正地组件编E。自?996q早些时候,Qtq入商业领域Q它已经成ؓ全世界范围内数千U成功的应用E序的基。Qt也是行的Linux桌面环境KDE 的基Q同时它q支持Windows、Macintosh、Unix/X11{多U^台?/p>
(3) WxWindows
参考网站:http://www.wxwindows.org/
跨^台的GUI库。因为其cdơ极像MFCQ所以有文章介绍从MFC到WxWindows的代码移植以实现跨^台的功能。通过多年的开发也是一个日完善的GUI库,支持同样不弱于前面两个库。ƈ且是完全开放源代码的。新q的C++ Builder X的GUI设计器就是基于这个库的?/p>
(4) Fox
参考网站:http://www.fox-toolkit.org/
开放源代码的GUI库。作者从自己亲n的开发经验中得出了一个理想的GUI库应该是什么样子的感受出发Q从而开始了对这个库的开发。有兴趣的可以尝试一下?/p>
(5) WTL
ZATL的一个库。因Z用了大量ATL的轻量手法Q模板等技术,在代码尺寸,以及速度优化斚w做得非常C。主要面向的使用体是开发COM轻量U供|络下蝲的可视化控g的开发者?/p>
(6) GTK
参考网站:http://gtkmm.sourceforge.net/
GTK是一个大名鼎鼎的C的开源GUI库。在Linux世界中有Gnomeq样的杀手应用。而GTK是q个库的C++装版本?/p>
5.4 |络通信
(1) ACE
参考网站:http://www.cs.wustl.edu/~schmidt/ACE.html
C++库的代表Q超重量U的|络通信开发框架。ACE自适配通信环境QAdaptiveCommunication EnvironmentQ是可以自由使用、开放源代码的面向对象框Ӟ在其中实C许多用于q发通信软g的核心模式。ACE提供了一l丰富的可复用C++包装外观QWrapper FacadeQ和框架lgQ可跨越多种q_完成通用的通信软gdQ其中包括:事g多\分离和事件处理器分派、信号处理、服务初始化、进E间?br />信、共享内存管理、消息\由、分布式服务动态(重)配置、ƈ发执行和同步Q等{?/p>
(2) StreamModule
参考网站:http://www.omnifarious.org/StrMod/
设计用于化编写分布式E序的库。尝试着使得~写处理异步行ؓ的程序更ҎQ而不是用同步的外壛_起异步的本质?/p>
(3) SimpleSocket
参考网站:http://home.hetnet.nl/~lcbokkers/simsock.htm
q个cd让编写基于socket的客?服务器程序更加容易?/p>
(4) A Stream Socket API for C++
参考网站:http://www.pcs.cnu.edu/~dgame/sockets/socketsC++/sockets.h
tml
又一个对Socket的封装库?/p>
5.5 XML
(1) Xerces
参考网站:http://xml.apache.org/xerces-c/
Xerces-C++ 是一个非常健壮的XML解析器,它提供了验证Q以及SAX和DOM API。XML验证在文档类型定?Document Type DefinitionQDTD)斚w有很好的支持Qƈ且在2001q?2月增加了支持W3C XML Schema 的基本完整的开放标准?/p>
(2) XMLBooster
参考网站:http://www.xmlbooster.com/
q个库通过产生特制的parser的办法极大的提高了XML解析的速度Qƈ且能够生相应的GUIE序来修改这个parser。在DOM和SAX两大LXML解析办法之外提供了另外一个可行的解决Ҏ?/p>
(3) Pull Parser
参考网站:http://www.extreme.indiana.edu/xgws/xsoap/xpp/
q个库采用pullҎ的parser。在每个SAX的parser底层都有一个pull的parserQ这个xpp把这层暴露出来直接给大家使用。在要充分考虑速度的时候值得试?br />
(4) Xalan
参考网站:http://xml.apache.org/xalan-c/
Xalan是一个用于把XML文档转换为HTMLQ纯文本或者其他XMLcd文档的XSLT处理器?/p>
(5) CMarkup
参考网站:http://www.firstobject.com/xml.htm
q是一U用EDOM的XML解析器。在很多思\上面非常灉|实用。值得大家在DOM和SAX之外L一点灵感?/p>
(6) libxml++
http://libxmlplusplus.sourceforge.net/
libxml++是对著名的libxml XML解析器的C++装版本
5.6 U学计算
(1) Blitz++
参考网站:http://www.oonumerics.org/blitz/
Blitz++ 是一个高效率的数D函数库Q它的设计目的是希望建立一套既具像C++ 一h便,同时又比Fortran速度更快的数D环境。通常Q用C++所写出的数值程序,?Fortran?0%左右Q因此Blitz++正是要改掉这个缺炏V方法是利用C++的template技术,E序执行甚至可以比Fortran更快。Blitz++目前仍在发展中,对于常见的SVDQFFTsQQMRES{常见的U性代数方法ƈ不提供,不过使用者可以很Ҏ地利用Blitz++所提供的函数来构徏?/p>
(2) POOMA
参考网站:http://www.codesourcery.com/pooma/pooma
POOMA是一个免费的高性能的C++库,用于处理q行式科学计。POOMA的面向对象设计方便了快速的E序开发,对ƈ行机器进行了优化以达到最高的效率Q方便在工业和研I环境中使用?/p>
(3) MTL
参考网站:http://www.osl.iu.edu/research/mtl/
Matrix Template Library(MTL)是一个高性能的泛型组件库Q提供了各种格式矩阵的大量线性代数方面的功能。在某些应用使用高性能~译器的情况下,比如Intel的编译器Q从产生的汇~代码可以看出其与手写几乎没有两L效能?/p>
(4) CGAL
参考网站:http://www.cgal.org/
Computational Geometry Algorithms Library的目的是把在计算几何斚w的大部分重要的解x案和Ҏ以C++库的形式提供l工业和学术界的用户?/p>
5.7 游戏开?/p>
(1) Audio/Video 3D C++ Programming Library
参考网站:http://www.galacticasoftware.com/products/av/
AV3D是一个跨q_Q高性能的C++库。主要的Ҏ是提供3D囑ŞQ声效支持(SB,以及S3MQ,控制接口Q键盘,鼠标和遥感)QXMS?/p>
(2) KlayGE
参考网站:http://home.g365.net/enginedev/
国内游戏开发高手自qC++开发的游戏引擎。KlayGE是一个开放源代码、跨q_的游戏引擎,q用Python作脚本语a。KlayGE在LGPL协议下发行。感谢龚敏敏先生Z国游戏开发事业所做出的A献?/p>
(3) OGRE
OGREQ面向对象的囑Ş渲染引擎Q是用C++开发的Q用灵zȝ面向对象3D引擎。它的目的是让开发者能更方便和直接地开发基?Dg讑֤的应用程序或游戏。引擎中的类库对更底层的pȝ库(如:Direct3D和OpenGLQ的全部使用l节q行了抽象,q提供了Z现实世界对象的接口和其它cR?/p>
5.8 U程
(1) C++ Threads
参考网站:http://threads.sourceforge.net/
q个库的目标是给E序员提供易于用的c,q些c被l承以提供在Linux环境中很隄到的大量的线E方面的功能?/p>
(2) ZThreads
参考网站:http://zthread.sourceforge.net/
一个先q的面向对象Q跨q_的C++U程和同步库?br />
5.9 序列?/p>
(1) s11n
参考网站:http://s11n.net/
一个基于STL的C++库,用于序列化PODQSTL容器以及用户定义的类型?/p>
(2) Simple XML Persistence Library
参考网站:http://sxp.sourceforge.net/
q是一个把对象序列化ؓXML的轻量的C++库?/p>
5.10 字符?/p>
(1) C++ Str Library
参考网站:http://www.utilitycode.com/str/
操作字符串和字符的库Q支持Windows和支持gcc的多U^台。提供高度优化的代码Qƈ且支持多U程环境和UnicodeQ同时还有正则表辑ּ的支持?/p>
(2) Common Text Transformation Library
参考网站:http://cttl.sourceforge.net/
q是一个解析和修改STL字符串的库。CTTL substringcd以用来比较,插入Q替换以及用EBNF的语法进行解析?/p>
(3) GRETA
参考网站:http://research.microsoft.com/projects/greta/
q是由微软研I的研Ih员开发的处理正则表达式的库。在型匚w的情况下有非怼U的表现?/p>
5.11 l合
(1) P::Classes
参考网站:http://pclasses.com/
一个高度可UL的C++应用E序框架。当前关注类型和U程安全的signal/slot机制Qi/opȝ包括Z插g的网l协议透明的i/o架构Q基于插件的应用E序消息日志框架Q访问sql数据库的cȝ{?/p>
(2) ACDK - Artefaktur Component Development Kit
参考网站:http://acdk.sourceforge.net/
q是一个^台无关的C++lg框架Q类gJava或?NET中的框架Q反机ӞU程QUnicodeQ废料收集,I/OQ网l,实用工具QXMLQ等{)Q以及对Java, Perl, Python, TCL, Lisp, COM ?CORBA的集成?/p>
(3) dlib C++ library
参考网站:http://www.cis.ohio-state.edu/~kingd/dlib/
各种各样的类的一个综合。大整数QSocketQ线E,GUIQ容器类,以及览目录的API{等?/p>
(4) Chilkat C++ Libraries
参考网站:http://www.chilkatsoft.com/cpp_libraries.asp
q是提供zipQe-mailQ编码,S/MIMEQXML{方面的库?/p>
(5) C++ Portable Types Library (PTypes)
参考网站:http://www.melikyan.com/ptypes/
q是STL的比较简单的替代品,以及可移植的多线E和|络库?/p>
(6) LFC
参考网站:http://lfc.sourceforge.net/
哦,q又是一个尝试提供一切的C++?/p>
5.12 其他?/p>
(1) Loki
参考网站:http://www.moderncppdesign.com/
哦,你可能抱怨我早该和Boost一起介l它Q一个实验性质的库。作者在loki中把C++模板的功能发挥到了极致。ƈ且尝试把cM设计模式q样思想层面的东襉K过库来提供。同时还提供了智能指针这h较实用的功能?/p>
(2) ATL
ATL(Active Template Library)
是一l小巧、高效、灵zȝc,q些cMؓ创徏可互操作的COMlg提供了基本的设施?/p>
(3) FC++: The Functional C++ Library
q个库提供了一些函数式语言中才有的要素。属于用库来扩充语言的一个代表作。如果想要在OOP之外L另一分的乐趣Q可以去看看函数式程序设计的世界。大师Peter Norvig?“Teach Yourself rogramming in Ten Years”一文中将函数式语a列ؓ臛_应当学习?cȝE语a之一?/p>
(4) FACT!
参考网站:http://www.kfa-juelich.de/zam/FACT/start/index.html
另外一个实现函数式语言Ҏ的?/p>
(5) Crypto++
提供处理密码Q消息验证,单向hashQ公匙加密系l等功能的免费库?/p>
q有很多非常Ȁ动h心或者是极其实用的C++库,限于我们的水q以及文章的幅不能包括q来。在对于q些已经包含q来的库的介l中Q由于ƈ不是每一个我们都使用q,所以难免有偏颇之处Q请读者见谅?/p>
--------------------------------------------------------------------------------
6Q书c?/p>
以前熊节先生曾撰文评论相对于JavaE序设计语言QC++的好书多如牛毛。荣耀先生在《程序员》杂志上撰文《C++E序设计之四书五l》也本领域内几乎所有的l典书籍作了全面的介l?M关于书的评论此时看来便是很多余的了。个人浅见,除非你打以C++作ؓ唯一兴趣或者生存之本,一般读者确实没有够的旉和必要将20余本书籍全部阅读。更有参考h值的是荣耀先生的另一文章:《至应该阅
ȝ九本C++著作》,可以从下面的地址览到此文:
http://www.royaloo.com/articles/articles_2003/9CppBooks.htm
下面几本书对于走在C++初学之\上的读者是我们最愿意推荐l大家的Q?/p>
(1) 《C++ Primer?/p>
哦,也许你会抱怨我们ؓ什么不先介lTCPL,但对于走在学习之路上的入门者,本书内容更ؓ全面Q更l易懂,我们U它为“C++的超U宝典”ƈ不过分。配有一本不错的习题解答《C++ Primer Answer Book》可以辅助你的学习之路?/p>
(2) 《Essential C++?/p>
如果说《C++ Primer》是C++领域的超U宝典,那么此书作ؓ掌握C++的大局观当之无愧。正如?NET大局观》一书能够让读者全?NETQ本书讲qCC++中最核心的全部主题。书虽不厚,内容_Q不׃ؓ《C++ Primer》读者茶余饭后的主题回顾之作?/p>
(3) 《The C++ Programming Language?/p>
BjarneZ带来的C++教程Q真正能够告诉你怎么用才叫真正的C++的唯一一本书。虽然如同“某某程序设计语a”这L书籍会给大家一个内容全揽,入门到精通的感觉Q但本书实不太适合初学者阅诅R如果你自认为是一名很有经验的C++E序员,那至也要反复咀嚼Bjarne先生所的若q内宏V?/p>
(4) 《Effective C++》,《More Effective C++?/p>
是的Q正如一些C++爱好者经总读过与没有读q上qC本作品来区分你是否是C++高手。我们也极力推崇q两本著作。在各种介绍C++专家l验的书c里面,q两本是最贴近语言本质Q看后最能够有脱胎换骨感觉的书,L书你需每日三省汝n?/p>
技术书c仁者见仁,q多的评论反无太多意义,p者喜好选择最适合自己的书方ؓ上策?/p>
--------------------------------------------------------------------------------
7Q资源网?/p>
正如我们可以通过计算机历史上的重要h物了解计机史的发展QC++相关人物的网站也可以使我们得到最有h值的参考与借鉴Q下面的人物我们认ؓ没有介绍的必要,只因下面的h物在C++领域的地位众所周知Q我们只相关的资源q行|列以供读者学习,他们有的工作于贝实验室Q有的工作于知名~译器厂商,有的在不断推q语a的标准化Q有的ؓ读者撰写了多部千古奇作…?br /> (1) Bjarne Stroustrup
http://www.research.att.com/~bs/
(2) Stanley B. Lippman
http://blogs.msdn.com/slippman/
中文?http://www.zengyihome.net/slippman/index.htm
(3) Scott Meyers
http://www.aristeia.com/
(4) David Musser
http://www.cs.rpi.edu/~musser/
(5) Bruce Eckel
http://www.bruceeckel.com/
(6) Nicolai M. Josuttis
http://www.josuttis.com/
(7) Herb Sutter
http://www.gotw.ca/
(8) Andrei Alexandrescu
http://www.coderncppdesign.com/
(9) 侯捷先生
http://www.jjhou.com/
(10) 孟岩先生
先生J忙于工作,痴迷于技术,暂无个h主页Q关于先生的作品可以通过CSDN的专栏和侯先生的主页讉K到?/p>
(11) 荣耀先生
http://www.royaloo.com/
(12) 潘爱民先?br /> http://www.icst.pku.edu.cn/panaimin/pam_homepage.htm
除了上述大师的主外Q以下的l合cC++学习参考站Ҏ我们非常愿意向大家推荐的Q?/p>
(1) CodeProject
http://www.codeproject.com/
(2) CodeGuru
http://www.codeguru.com/
(3) Dr. Dobb's Journal
http://www.ddj.com/
(4) C/C++ Users Journal
http://www.cuj.com/
(5) Cl视?br /> http://www.c-view.org/
(6) allaboutprogram
http://www.allaboutprogram.com/
其他资料
(1) ISO IEC JTC1/SC22/WG21 - C++Q标准C++的权威参?br /> http://anubis.dkuug.dk/jtc1/sc22/wg21/
(2) C++ FAQ LITE ?Frequently Asked Questions: 最为全面的C++FAQ
http://www.sunistudio.com/cppfaq/index.html
C/C++ 新闻l:
你不妨尝试从q里提问和回{问题,很多不错的Q&A资源......
(1) .alt.comp.lang.learn.c-c++
q个单些Q如果你和我一h个菜?/p>
(2) .comp.lang.c++.moderated
嗯,q个昄水^高一?/p>
(3) .comp.std.c++
如果你需要讨论标准C++相关话题的话
--------------------------------------------------------------------------------
8Q不得不写的l束?/p>
l束的时候也是ȝ现状Q展望未来的时候。虽然C++从脱胎于C开始,一路艰隑֝L走过来,但是无论如何C++已经取得了工业基的地位。文章列丄大量相关资源是最好的证明Q而业界的大量用C++写成的品代码以及大量的C++职业工程师则是最直接的证明。同Ӟ我们可以看到各个高校的计机专业都开设有C++q门评Q网l上对于C++的学习讨Z从来都没有停q。但是,在Java?NET两大企业开发^台的围攻下,lh的感觉是C++来“不行”了?/p>
C++在面向企业的软g开发中Q在开发便h等斚w的确要比Java和C#差很多,其中一个问题是C++语言本n比较复杂Q学习曲U比较陡峭,另外一个问题是C++标准化的旉太长Q׃很多的壮大机会,耗费了很多精力在厂商的之间的斗争上,而C++的标准库M个完善的E序开发框架还~少太多太多的内容,各个W三方的cd和框架又在一致性和完整性上没法和随q_提供的框架相提ƈ论。难道C++真的要退出历史舞CQ?/p>
从C++目前的活跃程度,以及应用现状来说是完全能够肯定C++仍然是Y件工业的基础Q也不会退出历史舞台的。另外从BoostQLokiq些库中我们也能够看到C++的发展非常活跃,对于新技术新思维非常Ȁq,C++仍然q泛受到x。从ACE在高性能通信领域的应用,以及MTLq样的库在数D领域的表现Q我们可以看到C++在高性能应用场合下的不可替代的作用,而嵌入式pȝq样的内存受限开发^?br />Q比如Symbian OS上,C++已经发挥着q且发挥更大的作用。可以预见的是以后的软g无论上层的应用怎么变,它的底层核心都会是由C/C++q样的系l软g~写的,比如Java虚拟机,.NET Framwork。因为只有这LpȝUY件才能完全彻底的发挥机器的功能?/p>
需要看到的是两个趋势,一个趋势是C++变得更加复杂Q更加学院派Q通过模板{有潜力的语法因素构造越来越_y的库成ؓ了现代C++的热点,虽然在利用库实现新的~程范式Q乃臌计模式等斚w很有开创意义,也确实生了一些能够便捷开发的工具Q但是更多的是把C++变得更加强大Q更加复杂,也更加难懂,g也更加学院派Q不得不说它正在向边~化道\发展。另一个趋势是C++在主的企业应用开
发中已经逐渐退ZQERPq样的企业Y件开发中基本上不会考虑C++Q除非需要考虑性能或者和遗留代码的集成这些因素。C++退守到pȝU别语言Q成Y件工业的基础是大势所。然而反思一下,真的是退守么Q自从STL出现Q无数的人风起云涌的开始支持C++,他们狂呼“我看到深夜消失了,目标软g工程的出现。我看到了可l护的代码。”是的,STL在可l护性下做得如此。但是又怎样呢?STL为C++铺^了现代Y件工E的道\Q而在上层应用E序软g开发领域这块场地早不单独属于C++,很多E序设计语言都做得很Q疯狂的支持者会毫不犹U地说我们应当支持C++,因ؓ它是世界上最的语言。而坦率地_你的腰杆真的那么么Q也许只是在逃避一些事实。C++是优U的,q不可否认,STL的出现让C++一度走上了最辉煌的时刻,然而现在看来……我的一位恩师曾aQ真正能够将STL应用得淋漓尽致的人很
保守地说国内也不过200人,或许不加入STL能够使C++向着它应当发展的方向发展的更好,而现在看来,C++也应当回首到真正属于他的那一片圣C…?/p>
By default, the COM Server code that the WTL AppWizard adds does not have the _Module.RegisterServer function set to TRUE by default. As a result, the type library information never showed up in the registry. A message in the ATL Archives relayed the answer to this problem.
After trying to use extended combo boxes within a WTL app and not getting them to load, I knew I must be doing something wrong. I was initializing them with ::InitCommonControlsEx() in OnInitDialog(), which was a little too late. I moved them to DllMain, and that solved the problem. (The Microsoft ATL mailing list archives saved the day ...)
I was trying to modify a WTL frame window by using ModifyStyle in OnCreate(). WTL doesn't like this very well. Instead I discovered that I got the results I was looking for by modifying CFrameWindowImpl to take a customized version of CWinTraits by adding it to the template definition. By the way, this also works for CWindowImpl, which is where I found this trick in the MSDN docs and ATL Internals. Also, this link shows another tricky portion of the whole process.
Steps to use CDialogResize (from WTL 3.1):
1) #include <atlframe.h> in your view/dialog class
2) derive your view/dialog from CDialogResize:
class CMyClass: public CDialogImpl<CMyClass>, ....
public CDialogResize<CMyClass>
3) Add a DLGRESIZE_MAP to your view as follows:
BEGIN_DLGRESIZE_MAP(CMyClass)
DLGRESIZE_CONTROL(IDOK, DLSZ_MOVE_X | DLSZ_SIZE_Y)
END_DLGRESIZE_MAP()
The first parameter in the DLGRESIZE_CONTROL macro is the resource ID of your control. The second parameter(s) is the way that you want that control to be resized; valid values are DLSZ_MOVE_X, DLSZ_MOVE_Y, DLSZ_SIZE_X, DLSZ_SIZE_Y. (Note that you can OR these together with a |). You can also resize controls as a group by enclosing a number of DLGRESIZE_CONTROL macros with BEGIN_DLGRESIZE_GROUP() and END_DLGRESIZE_GROUP(). More on grouping in the next tip.
4) Chain your message map to CDialogResize, i.e.
BEGIN_MSG_MAP(CMyClass)
....
CHAIN_MSG_MAP(CDialogResize<CMyClass>)
END_MSG_MAP()
5) Initialize the resizing for your view with DlgResize_Init(false, true, WS_CLIPCHILDREN) in OnInitDialog. Normally (for standard dialogs) you would just use DlgResize_Init() and accept the default parameters, but for a view you have to supply the extra settings since the view doesn't need a gripper or a frame like a dialog would.
Some things I've noticed about grouping controls with CDialogResize:
1) You can group controls in one direction and leave them ungrouped in another direction to achieve good effects.
For instance, if you had Save, Print and Close buttons running along the bottom of your dialog, centered and spaced evenly apart, you'd probably want to do this grouping:
BEGIN_DLGRESIZE_MAP(CMyClass)
BEGIN_DLGRESIZE_GROUP()
DLGRESIZE_CONTROL(IDC_BTN_SAVE, DLSZ_MOVE_X )
DLGRESIZE_CONTROL(IDC_BTN_PRINT, DLSZ_MOVE_X )
DLGRESIZE_CONTROL(IDC_BTN_CLOSE, DLSZ_MOVE_X)
END_DLGRESIZE_GROUP()
DLGRESIZE_CONTROL(IDC_BTN_SAVE, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_PRINT, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_CLOSE, DLSZ_MOVE_Y)
END_DLGRESIZE_MAP()
This would keep all of them centered and spaced evenly as you moved them, while also moving them up and down independently.
2) As soon as you noticed this little trick, however, you might start to take notice that your buttons don't exactly line up with the other controls on screen. You'd see this as the dialog was sized larger and larger. What's happening is that the leftmost button in the resource (this doesn't mean the top one in the DLGRESIZE_GROUP -- it's unrelated) is acting as an anchor for all the other buttons in the group. So when you resize the dialog, the leftmost button isn't moving ... it's just staying in place.
There may be better ways to solve this problem, but what I did is insert a new invisible button on the resource in the leftmost position to act as the anchor. I then included the button in the DLGRESIZE_GROUP with a DLSZ_MOVE_X command as well so it would make all the other three buttons move together correctly. Like I said -- it works. If you stumble on something better
WTL 最l来?/span> , 而且 提供了我所希望的功?/span> . 我在 WTL Bytesize (译文)的文章列?/span> WTL 主要特征 . 在本文中 , 我将描述一?/span> WTL 的体pȝ?/span> , 同时我会l出一些简单的例子来演C如何用它的那些特?/span> . 希望能够Ҏ?span lang="zh-cn">所帮助 .
WTL 应用E序的类?/font>
WTL 有好几种应用E序cd , 供您?/span> AppWizard 选取 .
下表对这些应用程序进行了描述
.
q种Ҏ构成了
WTL
体系l构的一部分
.
应用E序cd | 描述 |
SDI Application | 单文本界?/span> ? 只有一个窗?/span> |
Multiple Threads SDI | 单个q程拥有一个或多个H口 |
MDI Application | 多文本界?/span> ? 在框架内 , 您可以有零个或多个子H口 |
Dialog Based | Z对话框模?/span> |
你可能还是首ơ听说多U程SDI应用E序,但是不用担心,它的概念很容易理?一个多U程SDIE序启动后它会有一个窗? H口昄了一个文? 当你惌E序要再创徏一个文档时,问题出C--SDIE序只能昄一个文?Z解决q个问题,多线ESDI创徏了另一个SDIH口.看v来是一个新的实例在q行,实际上它不过是原来的q程创徏了一个新的窗?q把它依附到q程的一个新U程. IE的新建窗口就是这样做?
除了多线E?span lang="EN-US">SDI,所有这些应用程序都可以作ؓCOM服务? q且应用E序向导(AppWizard)为此提供了一个选项.另外应用E序向导q可以让你指定该E序是否LActiveX控g.令h费解的是,不同的程序类?选取"Host ActiveX Controls"的地方不?除对话框应用E序外的其他cd在第一上选取,而对话框cd却放到第二页.
W二늚其他选项,对对话框E序以外的类型都是可用的.它们让你指定E序是否需要工h(toolbar),状态条(status bar)和视H口(View Window).
如果选取?Toolbar"选项,你可以通过"Rebar"选择是否工h攑օIE Rebar控g? 如果你选取了Rebar, 你就可以通过框架H口(frame window)的成员m_hWndToolBar(后边会有详细的描q?来访问它.你可以按照你的意?在里边加入其他的工具? 选取?Rebar"? 你可以决定是否选取"Command Bar".
Command bar很像CE的command bar控g.只是WTL是用一个类来实?而在CE, command bar是一个系l窗口类(system window class). Command bar非常有用,它能够把H口也加入到工具条中? 如果你选取了这个选项, 工具条和菜单都将被当做toolbar来实?q菜单也可以有关联的图标,q且当你Ud鼠标C个菜单项上时,该菜单项会被|成高亮.从Office 97以来, Office软g的菜单都h上述特征.
W二还有指定程序是否用视的选项(多半你想要?, 同时你可以决定这些视如何实现. 下表列出了所有可选的?
?/span> | 描述 |
Generic Window | 一个简单的H口 . 此类H口允许E序员编?/span> WM_PAINT 消息的处理函?/span> . 适用于需要直接进?/span> paint 的文?/span> . |
Form | q类视具有一个对话框模版 . 适用于带 ActiveX 控g的窗?/span> . 应用E序来操作这些控?/span> . |
List Box | q个视是?/span> list box. 它最单的形式意味着可以通过调用 AddString() Ҏ来添加字W串 . |
Edit | q个视是?/span> edit control. 本质?/span> , 它提供了一个像 Notepad 一LE序 . |
List View | q个视是?/span> list view 通用控g . 用这个控件来昄相关的项 ( 比如 , 控制面板是一?/span> Explorer L?/span> List View, 所有的w是控刉?/span> applet). |
Tree View | q个视是?/span> tree view 通用控g . q个适用于具有层ơ关pȝ数据 , 比如 , 可以用它来显C数据库?/span> schema. 层分支和存储过E?/span> , ơ的分支ؓ表中的字D?/span> . |
Rich Edit | q个视是?/span> rich edit 控g , ?/span> WordPad. |
HTML Page | q个视主持了一?/span> IE Web Browser 控g . 它把L的一?/span> web page 当成一个视 . |
本文的例子需要一个对话框模版
,
同时q需要菜?/span>
,
因此
Form view
是个理想的选择
.
E序U程
跟ATL一?WTLE序也需要一?font face="Courier New">_Module全局变量来保存全局数据,方便应用U代码访?在WTL?q个变量?font face="Courier New">CAppModule?font face="Courier New">CServerAppModule的实?后者在E序同时作ؓ一个COM服务器时用到.每个应用E序h一个或者多个UIU程.WTL使用两种方式来管理这些线E?
如果应用E序只有一个UIU程(除了多线ESDI以外,其他E序cd默认只有一个UIU程),U程调用全局函数run():
int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT)
{
CMessageLoop theLoop;
_Module.AddMessageLoop(&theLoop);
CMainFrame wndMain;
if (wndMain.CreateEx() == NULL)
{
ATLTRACE(_T("Main window creation failed!\n"));
return 0;
}
wndMain.ShowWindow(nCmdShow);
int nRet = theLoop.Run();
_Module.RemoveMessageLoop();
return nRet;
}
U程的消息@环包含在CMessageLoop内部.函数创徏了一?b>CMessageLoop实例, 把它攑օ全局的消息@环映?message loop map)数组. 以线EID为烦?U程中运行的其他的代码可以访问到q个实例. 消息循环对象包含了message filter和idle handler. q行在这个UIU程的UI元g(UI element)可以有它自己的idle handler,在线E的消息队列为空时运?font face="宋体">?/font>译注:通过CMessageLoop::AddIdleHandler()把这个UI元g加入?b>CMessageLoop的idle handler 数组?font face="宋体">?/font>. CMessageLoop::Run()包含了UIU程的主消息映射(main message map).下边是它的伪代码:
MSG m_msg;
int CMessageLoop::Run()
{
for (;;)
{
while (!::PeekMessage(&m_msg, NULL, 0, 0, PM_NOREMOVE))
DoIdleHandlers();
bRet = ::GetMessage(&m_msg, NULL, 0, 0);
if(bRet == -1)
continue;
else if(!bRet)
break;
if (!DoMessageFilters(&m_msg))
{
::TranslateMessage(&m_msg);
::DispatchMessage(&m_msg);
}
}
return (int)m_msg.wParam;
}
可以看到,q个函数推动着消息队列. 没有消息? q行注册到线E的idle hander. 如果在队列中到消息,把它取出?传给每个message filter. 如果消息没有被这些函数处?它将按照通常的方?发送到目标H口.
如果E序有超q一个的UIU程,可以用WTL的线E管理器,多线ESDI是q样做的. ȝE作Z个管理者线E?它会为每个新H口创徏一个新?span lang="zh-cn">?/span>U程. 主要程如下:
int nRet = m_dwCount;
DWORD dwRet;
while(m_dwCount > 0)
{
dwRet = ::MsgWaitForMultipleObjects(m_dwCount, m_arrThreadHandles,
FALSE, INFINITE, QS_ALLINPUT);
if(dwRet >= WAIT_OBJECT_0 && dwRet <= (WAIT_OBJECT_0 + m_dwCount - 1))
RemoveThread(dwRet - WAIT_OBJECT_0);
else if(dwRet == (WAIT_OBJECT_0 + m_dwCount))
{
::GetMessage(&msg, NULL, 0, 0);
if(msg.message == WM_USER)
AddThread(_T(""), SW_SHOWNORMAL);
}
}
那些U程句柄攑֜一个数l中. U程通过AddThread()加入到数l?同时启动U程), RemoveThread()从数l移? wait语句在两U情况下会被打断: U程M(线E从数组中移? 或线E收CWM_USER消息(一个线E在一个新U程里新Z一个窗?. U程理者ؓE序中的一个类,因此可以在@环中加入自己的message handler, 比如,当程序有不止一U窗口类型时. 创徏一个新的窗口非常简?只需在Q意一个窗口中调用:
::PostThreadMessage(_Module.m_dwMainThreadID, WM_USER, 0, 0L);
q个循环会一直运行下?直到所有的UIU程都关闭了. UIU程h一个thread procedure,它跟单UIU程的Run()Ҏ一?不过,׃U程理者用了MsgWaitForMultipleObjects(), q意呌最多只能有MAXIMUM_WAIT_OBJECTS-1个UIU程,q也意味着最多只能创?3个窗?
框架
WTL实际上是两类H口: 框架H口和视囄? 正如名字所暗示的那? 框架H口为窗口提供标题栏(caption bar)和边?你的代码用它来处理工h(tool bar)和菜单项命o.你看到的E序H口实际上是视图H口, 视图覆盖了框架窗口的客户?客户区是指框架窗口没有被诸如状态条,工具条之cȝ修饰部g所遮挡的部?
U程会创Z框架H口的一个实?创徏视图的工作由L架窗口的WM_CREATE消息处理函数完成. 对于SDIE序来说,q个q程很简? 把视囄的一个实例作Z框架cȝ一个成?调用视图cȝCreate()Ҏ卛_.MDIE序E微有些不同, MDIL架窗口通过CMDIFrameWindowImpl<>::CreateMDIClient()建立一个名?b>MDICLIENT的窗? q个客户H口?font face="Courier New">CMDIChildWindowImpl<>H口当做它的子窗?子窗口有一个视?q也反映了这么一个事?MDIE序可以h零个或者多个子H口,每个都有Ҏ和标题栏.
框架H口的OnCreate()很有意?让我看看:
LRESULT OnCreate(UINT, WPARAM, LPARAM, BOOL&)
{
// create command bar window
HWND hWndCmdBar = m_CmdBar.Create(m_hWnd, rcDefault,
NULL, ATL_SIMPLE_CMDBAR_PANE_STYLE);
// attach menu
m_CmdBar.AttachMenu(GetMenu());
// load command bar images
m_CmdBar.LoadImages(IDR_MAINFRAME);
// remove old menu
SetMenu(NULL);
HWND hWndToolBar = CreateSimpleToolBarCtrl(m_hWnd, IDR_MAINFRAME,
FALSE, ATL_SIMPLE_TOOLBAR_PANE_STYLE);
CreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE);
AddSimpleReBarBand(hWndCmdBar);
AddSimpleReBarBand(hWndToolBar, NULL, TRUE);
CreateSimpleStatusBar();
m_hWndClient = m_view.Create(m_hWnd, rcDefault, NULL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
WS_EX_CLIENTEDGE);
UIAddToolBar(hWndToolBar);
UISetCheck(ID_VIEW_TOOLBAR, 1);
UISetCheck(ID_VIEW_STATUS_BAR, 1);
CMessageLoop* pLoop = _Module.GetMessageLoop();
pLoop->AddMessageFilter(this);
pLoop->AddIdleHandler(this);
return 0;
}
q是从一个SDIE序拿来的一D代?该程序有一个基于command bar的工h和一个状态条. 函数的第一行创Z一个command bar实例,然后对它q行初始?在其中加入框架窗口的菜单和工h位图. q段代码先将菜单取出,把所有的下拉菜单转换为工h按钮,q将菜单保存在一个变量中,以备后用. lh的感觉是菜单是由工具条实现的-那我们就把它叫做工具条菜?menu toolbar)? 然后Command Bar程序工h的图标装入image list q将它们的ID保存在数l中. 当点dh菜单的按钮时,commandbar会找到对应的子菜?创徏一个弹? Command bar子菜单的ID和它保存的IDq行比较,q些ID跟image list中的工具条按钮图标是相关联的. 如果比较成功, 则将兌的图标加到菜单项上去. q意味着相同ID的菜单项和工h按钮h相同的图?
接下? 创徏工具条ƈ把它兌到commandbar, 然后创徏状态条和视?可以看到视图?b>HWND存放在框架窗口的m_hWndClient变量? q个H口句柄在框架窗口的WM_SIZE handler中会用到.当框架窗口改变大时,它告知视图改变自w?于此同时也要考虑状态条和command bar.
在下来的三行(从调?b>UIAddToolBar()开? 用来昄在运行时会改变状态的UI?UI item).文章后面q会重提q个话题. 最?讉K消息循环(message loop), 你应该还记得该消息@环存攑֜一全局数组?GetMessageLoop() 取得当前U程的消息@?加入框架H口的message filter和idle handler, 分别默认?b>PreTranslateMessage()?b>OnIdle().
框架H口l承于以下类:
class CMainFrame :
public CFrameWindowImpl<CMainFrame>,
public CUpdateUI<CMainFrame>,
public CMessageFilter,
public CIdleHandler
后两个抽象类宣称了框架窗口类实现?b>PreTranslateMessage()?b>OnIdle(). ?b>CUpdateUI<>l承表示框架cL持UI update map.
视图
视图H口看v?/span>昑־很简?
class CMyView : public CWindowImpl<CMyView>
{
public:
DECLARE_WND_CLASS(NULL)
BOOL PreTranslateMessage(MSG* pMsg)
{
pMsg;
return FALSE;
}
BEGIN_MSG_MAP(CMyView)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
END_MSG_MAP()
LRESULT OnPaint(UINT, WPARAM, LPARAM, BOOL&)
{
CPaintDC dc(m_hWnd);
//TODO: Add your drawing code here
return 0;
}
};
上面?/span>一个SDIE序的视囄. 多线ESDI和MDI的视囄在本质上?span lang="zh-cn">跟这?/span>一?但他们没?b>PreTranslateMessage()Ҏ. SDIE序是使用q个函数,赶在框架c?span lang="zh-cn">处理消息之前把消?/span>抓住. PreTranslateMessage()在SDI的框架类中的实现?span lang="zh-cn">Q?/span>直接?/span>消息转发l视囄.
q里昄的视囑֮际上没有做什么工?你应?span lang="zh-cn">自己?b>OnPaint()函数中加入画出文?span lang="zh-cn">内容的代?如果需要支持输?如鼠标的点击和键盘的按键,你应该加?span lang="zh-cn">相应消息处理函数到类和映中. 可以?span lang="zh-cn">?/span>q个H口是从CWindowImpl<>l承下来?如果你想让它Z一个Win32控g的话,应该从定义在AtlCtrls.h文g?span lang="zh-cn">某个WTLcȝ?
如果惛_ZCWindowImpl<>的类里加上滚动条,那么你应该把基类换成CScrollWindowImpl<>,同时把消息链l它:
class CMyView : public CScrollWindowImpl<CMyView>
{
public:
typedef CScrollWindowImpl<CMyView> parent;
BEGIN_MSG_MAP(CMyView)
CHAIN_MSG_MAP(parent)
END_MSG_MAP()
void DoPaint(CDCHandle dc)
{
}
}Q?/span>
基类保证H口?span lang="zh-cn">?/span>滚动?q提供滚动条消息的默认处?视图cM再有WM_PAINT的处理函?因ؓ?span lang="zh-cn">?/span>?b>CScrollWindowImpl<>处理.Ҏ滚动条的位置,CScrollWindowImpl<>d视图相对应的部分. 取而代?span lang="zh-cn">?/span>?span lang="zh-cn">Q?/span>在你的类里实?b>DoPaint(),在这里你需要画?span lang="zh-cn">?/span>个视?如果?span lang="zh-cn">?/span>指定滚动的范?大小或v?你需要加上处?b>WM_CREATE消息的函?span lang="zh-cn">Q把q些初始?/span>代码攑ֈ里边.
正如我先?span lang="zh-cn">所提到?框架H口会改变视囄口的大小,以它客户区未被状态条和工h覆盖的部分ؓ视图所填充. 在大多数情况?q样够?/span>.但是当你惌一个具有Windows Explorer样子的程序时,该怎么办呢? Windows Explorer的窗口包含了一个tree view 和一个list view,q有两者之间的分割? WTL的解x案很?使用splitterH口!
为此你需要改变一下框架窗?让它创徏splitterH口的一个实例作为它的视? 例如, 在你?span lang="zh-cn">框架c里有如下的数据成员:
CSplitterWindow m_view;
CTreeViewCtrl m_tree;
CListViewCtrl m_list;
你可以在OnCreate()创徏一个splitterH口:
// get the frame client rect, so that we set the splitter initial size
// and we can get the splitter bar in the centre
RECT rect;
GetClientRect(&rect);
m_hWndClient = m_view.Create(m_hWnd, rect,
NULL, WS_CHILD | WS_VISIBLE);
m_tree.Create(m_view, rcDefault, NULL,
WS_CHILD | WS_VISIBLE | TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT,
WS_EX_CLIENTEDGE);
m_list.Create(m_view, rcDefault,
NULL, WS_CHILD | WS_VISIBLE | LVS_REPORT, WS_EX_CLIENTEDGE);
m_view.SetSplitterPanes(m_tree, m_list);
m_view.SetSplitterPos();
SplitterH口如同一个视?框架窗口作为它的父H口. 在这D代码里,我将框架H口客户区的实际大小传给?/span>splitterH口. ?span lang="zh-cn">?/span>可以在这里?rcDefault,因ؓ一旦框架窗?span lang="zh-cn">创徏完成,框架H口?/span>会{?b>WM_SIZE消息lsplitter. q样splitter可以马上改变自n的大来填充框架. 然?当我准备使用?span lang="zh-cn">?/span>参数?b>SetSplitterPos(),把分割条讄于窗口中U时,出现了问?SplitterH口使用它的大小来决定中U的位置,׃rcDefault告诉H口它的大小?(因此中线的位|也?),从而意味着分割条将出现?span lang="zh-cn">z最左边,?/span>左窗口隐藏了h.
创徏了splitterH口?你需要创建那些你惌分割的窗?span lang="zh-cn">?/span>.它们作为splitterH口?span lang="zh-cn">?/span>H口被创?最后你这些子H口通过SetSplitterPanes()加到splitterH口中去,q确定分割条的位|所?
UI Update
菜单可以被讄为有效或无效,可以?/span>check记号或着像radio按钮一??/span>一l?span lang="zh-cn">菜单中同时有且只有一?span lang="zh-cn">能被check.此外,菜单还可以带图标和文字. 所有的q些状态都可以在运行时ҎE序中的某个D行改?工具条在某种E度上可以看做是菜单的易见Ş?因ؓ它们的按钮可以个别地,或者作Zl的一?span lang="zh-cn">?/span>被置成有效或无效,推入推出. UI update机制允许你指定哪些UI元g(UI element)的状态可以在q行时改? WTL使用如下的UI update映射来实现这一功能:
BEGIN_UPDATE_UI_MAP(CMainFrame)
UPDATE_ELEMENT(ID_FILE_SAVERESULTS, UPDUI_MENUPOPUP | UPDUI_TOOLBAR)
UPDATE_ELEMENT(ID_VIEW_TOOLBAR, UPDUI_MENUPOPUP)
UPDATE_ELEMENT(ID_VIEW_STATUS_BAR, UPDUI_MENUPOPUP)
END_UPDATE_UI_MAP()
q个例子指出三个菜单在q行时有一个状态需要显C?其中的一? ID_FILE_SAVERESULTS,q?/span>有一个工h按钮跟它相关? WTL通过建立一个数l来保存q些信息.为此你需?span lang="zh-cn">完成两方面的工作:
首先是UI元g的状? 如果是菜单项, 你可以?b>UIEnable()使能该菜单项, UISetCheck()讄check记号, UISetText()改变菜单的文?如果是工h按钮,那么你?b>UIEnable()使能该按? UISetCheck()或?font face="Courier New">UISetRadio()军_按钮是推入还是推?下边的代码根据是否有文本被选中,来能Cut菜单和工具条按?
BOOL bSelected = GetSelected();
UIEnable(ID_EDIT_CUT, bSelected);
你可以把q样的代码放?span lang="zh-cn">相应处理函数?如一个菜单项的状?/span>依赖于另一个菜单项的动?span lang="zh-cn">,它攑օ后者的处理函数?/span>),或者放?font face="Courier New">OnIdle()Ҏ,通过查某个类变量来决定元件的状?
其次是确定各个UI元g是否都被更新?为此你需要调?font face="Courier New">CUpdateUI<>的某?/span>Ҏ?/span>UI元g加入到列表中.主菜单已?/span>自动加入,但是其他的Q何菜单和所有的工具条必d别通过调用UIAddMenuBar()?b>UIAddToolBar()手动加入.
其他q有一堆事情要注意. 首先,讄了工h的状态后,使用UIUpdateToolBar()以工具条状态更? 对于菜单,你不需如此,因ؓ子菜单是动态生成的.UIUpdateMenuBar()q个Ҏ也存?但是?span lang="zh-cn">的作?/span>是把菜单恢复到初始状?如果你改变过某些的文字,调用UIUpdateMenuBar()的结果可能不是你所期望?因ؓ菜单的文字会变?span lang="zh-cn">?/span>?.
管q有一个方?b>UISetRadio(),但是q?/span>没有一个把几个菜单Ҏ者工h按钮当做radio按钮l?也就是说,有一个而且只有一个被选中)的机?如果你希望得到这?span lang="zh-cn">效果,你必自q?不过它ƈ不难.
对话?/font>
ATL的对话框支持一向很?ҎWTL新增了通用对话框的装. 本质上是为对话框加入了输入验证和回调函数. 比如, 你想?/span>用户改变qOpen对话框中的文件夹时有所动作,那么你应该从CFileDialogImpl<>l承一个类,实现OnFolderChange():
class CMyFileDialog : public CFileDialogImpl<CMyFileDialog>
{
public:
CMyFileDialog(BOOL b)
: CFileDialogImpl<CMyFileDialog>(b) { }
void OnFolderChange(LPOFNOTIFY lpon)
{
char strFolder[MAX_PATH];
if (GetFolderPath(strFolder, sizeof(strFolder)) > 0)
{
MessageBox(strFolder);
}
}
};
当文件夹的\径改变时,CFileDialogImpl<>调用OnFolderChange().该函C用基cȝGetFolderPath(),来取得新路径.
控g
WTL为所有的Win32和通用控g提供了封装类,包括Windows 2000新加入的. 虽然只是单的包装Q但是它们ɘq些控g更加Ҏ讉K.譬如Q你能记清楚从List Viewd当前选定的文字的消息和需要传的参数吗Q?实际? 你需要发送两个消? 一个是得到选定的索引Q另一个是d它的文字.) WTL的作?span lang="zh-cn">Z完成了这些烦人的工作, 提供了一个简单的装函数供你使用.
使用q些控gcL两种Ҏ. 如果你的对话框里有一个控? 你可以将控g?font face="Courier New">HWND依附C个封装对?使用装cȝҎ来访问控?span lang="zh-cn">.q种Ҏ化了你读写控件数据和处理notification消息的代?
另外的用法是把这些类加到你的视图cȝl承层次中去:
class CMyView : public CWindowImpl<CMyView, CListBox>
q表C?font face="Courier New">CWindowImpl<>?font face="宋体">?/span>CListBoxl承而来,因此创徏的窗口将是一个list box (因ؓH口cȝ名字是通过调用
CListBox::GetWndClassName()得到?/span>). 另外, ATL的窗口机制会子类化这个窗?发l它的消息\由到你的消息映射中去. 它保留了老的H口函数,q样,你没有处理的消息由老的H口函数来处?当你的视囄从控件类l承?WTL׃使用q一技?
在notification消息和子cdq个主题?有一点很值得指出,那就是当?/span>事g发生?l大多数H口控g都会发送notification消息l它们的父窗?让你H口来处理这?font face="Courier New">notification消息要比子类化一个已存在控gH口(或子cd一个已存在的类,然后建立一个实?,从而在控g之前取得消息好得? 譬如, 你想处理按钮的click事g,你所需要做的只是处?font face="Courier New">BN_CLICKEDnotification.它将由按钮发送给你的H口c?另外的一U方法是?b>CContainedWindow<>子类化BUTTONH口来处?b>click消息.
?span lang="zh-cn">之所?/span>说这个是因ؓ一个知名的ATL鼓吹者给我一份代码里是q么做的.他的代码取得一个简单的按钮click事g所q旉是别人的3??因ؓ他子cd了按钮控?而不是简单的处理BN_CLICKEDnotification.
WTLq提供了一些新的控?在win32中没有对{? 你已l看到过一?span lang="zh-cn"> -- command bar, 实际上还有其他一些非常有用类:
c?/span> | 描述 |
CBitmapButton | q是一个用位图替代标题的按?你可以提供一?/span>image list,里边包含按钮在正常状?失效, 推入和鼠标落在按钮上的图?/span>. |
CHyperLink | 让你建立一个static控g,它代表一?/span>hyperlink,q样当用Ld?默认的web览器打开该链?/span>. |
CWaitCursor | q不q是在它的构造函C把鼠标图标改成等待状?而在析构函数中还?/span>. |
CCheckListViewCtrl | 在每一边上都有一个check box?/span>list box. |
CMultiPaneStatusBarCtrl | h多个pane的状态条 |