??xml version="1.0" encoding="utf-8" standalone="yes"?>久久97久久97精品免视看秋霞,狠狠色婷婷久久综合频道日韩,中文字幕无码免费久久 http://www.shnenglu.com/ace/category/1169.html<table style="border:1px solid #aa0033; font-size:small" align=center>
<tr>
<td rowspan=3>
</td>
<td colspan=2 align=center><b>订阅 ace-china</b></td>
</tr>
<form action="http://groups.google.com/group/ace-china/boxsubscribe">
<input type=hidden name="hl" value="zh-CN">
<tr>
<td>电子邮gQ?<input type=text name=email></td>
<td>
<table
style="background-color:#ffcc33;padding:2px;border:2px outset #ffcc33;">
<tr>
<td>
<input type=submit name="sub" value="订阅">
</td>
</tr>
</table>
</td>
</tr>
</form>
<tr><td colspan=2 align=center> 览存于
<a >groups.google.com</a> 上的<a >所有帖?lt;/a> </td></tr>
</table> zh-cn Tue, 20 May 2008 01:09:29 GMT Tue, 20 May 2008 01:09:29 GMT 60 在Visual Studio 2005下用CPPUnit向导 http://www.shnenglu.com/ace/archive/2006/08/04/10842.htmlStone Jiang Stone Jiang Fri, 04 Aug 2006 07:35:00 GMT http://www.shnenglu.com/ace/archive/2006/08/04/10842.html http://www.shnenglu.com/ace/comments/10842.html http://www.shnenglu.com/ace/archive/2006/08/04/10842.html#Feedback 1 http://www.shnenglu.com/ace/comments/commentRss/10842.html http://www.shnenglu.com/ace/services/trackbacks/10842.html 使用CPPUnitProjectWizard向导创徏支持使用CPPUnit的测试类的Visual Studio 2005目?/p>
安装向导 0. 下蝲 CPPUnitProjectWizard http://cppunit.sourceforge.net/cppunit-wiki/CppUnitVisualStudio2005Wizard?action=AttachFile&do=get&target=CPPUnitProjectWizard.7z
1. 复制文g CPPUnitProjectWizard.vsdir - 为向导命?br /> CPPUnitProjectWizard.vsz - 让VS8知道从哪里找到向?br /> 到您的Visual Studio 8安装目录下的 VSProjects 文g夹中?br /> 2. 把整个CPPUnitProjectWizard解决Ҏ文g夹复制到您的Visual Studio 8安装目录下的VCWizards文g夹中?br /> 比如Q我攑֜c:\Program Files\Microsoft Visual Studio 8\VC\VCWizards\CPPUnitProjectWizard\CPPUnitProjectWizard 或者,也可以放在你x|的其它地方Q然后编译CPPUnitProjectWizard.vszQ定义参?ABSOLUTE_PATH Param="ABSOLUTE_PATH = c:\Program Files\Microsoft Visual Studio 8\VC\VCWizards\CPPUnitProjectWizard\CPPUnitProjectWizard" 3. 该项目需要定义环境变?CPPUNITDIR 比如Q我的环境变量?%CPPUNITDIR% = D:\cppunit-1.12.0 最后,修改 环境变量 %PATH%,在PATH路径中,增加 %CPPUNITDIR%/libQ以便程序加载时能找?cppunit_dll.dll 4. 在开发环境中Q设|好Include/Lib路径 %CPPUNITDIR%\Include %CPPUNITDIR%\LIB
]]> 面向对象vsZ对象 http://www.shnenglu.com/ace/archive/2006/06/25/8985.htmlStone Jiang Stone Jiang Sun, 25 Jun 2006 08:18:00 GMT http://www.shnenglu.com/ace/archive/2006/06/25/8985.html http://www.shnenglu.com/ace/comments/8985.html http://www.shnenglu.com/ace/archive/2006/06/25/8985.html#Feedback 0 http://www.shnenglu.com/ace/comments/commentRss/8985.html http://www.shnenglu.com/ace/services/trackbacks/8985.html 面向对象vsZ对象
看到了一U说法,很多所谓面向对象开发只不过是基于对象的开?wbr>。反思自w,发觉一针见血?/wbr>
我们所谓的面向对象Q实际上只不q封装了业务对象Q分Z层次Q提供了接口。虽然在设计和实现的时候用到了面向对象的装Q但现在看来q算不上真正的面向对象,只能是Z对象而已?/wbr>
面向对象的原则ƈ没有W合。面向对象的优势也没有发挥,反而感觉一个小变化q扯到多层的变动,ȝ。就好比d的项目,数据库采用ORACLEQ实际本w对ORACLEq不熟悉Q只l过不到一周的学习Q就上马了。结果只不过ORACLE当成MSSQL使用。ORACLE的强大不但没有体玎ͼ到现在也没有搞明白)Q反而失MMSSQL的好的经验。得不偿失?
不过Q如何才真正的面向对象呢?想了想一个好的面向对象的实践Q应该是辑ֈ最大限度的软g复用Qƈ且可以快速适应不断变化的需求,而对已有的部分媄响最?wbr>?/wbr>
q不是一y而就的事情,如果想真正的用项目来实践的话Q正的步骤也许应该是:
首先采用本n较熟悉的开发方法(Z对象或是面向q程Q满业务需?wbr>。这一步很关键Q只有有了这样一个原型才可以验证寚w求的满E度。个人感觉直接面向对象会陷入设计q度Qƈ且在前期耗费大量?wbr>_֊。更重要的是使用不熟悉的技术会带来风险Q得不偿失?/wbr>
然后逐渐的将采用真正的面向对象的Ҏ现有的原型q行重构。目的是提高性能Q灵zL?wbr>Q扩展性,可复用性等{,q是一个长期的不断q代的过E。可以参看经典的《重?改善代码质量》?/wbr>
最后一步是架构的提点{将pȝ中的可以外部复用的部分提炼出来Ş?wbr>一个可以复用的框架架构。有了它Q以后的开发相会事半功?wbr>。此步骤会用到重构和设计模式。整个的q程除了W一步和面向对象无大关系外,后两步则完全的面?wbr>对象的思想?/wbr>
在此之前L希望先有一个设计良好的架构Q一直这样不断的学习和进行实c结果却不尽人意。经验说明这样做实有些本末倒置。正如模式的使用一?wbr>Q在动机不明的情况下盲目的套用模式是没有意义的?/wbr>
每一个开发h员的脑袋中有一些非常美妙的创意Q这些创意没有实现的一个原因就是,太过xl节。对于面向对象还是基于对象开发,对于实现需求,完成目的初期阶D,真的无所谓。当需要考虑提高开发和l护效率的时候,面向对象成了很不错的选择?/div>
]]>
E序员的八荣八?-- 来源不详 http://www.shnenglu.com/ace/archive/2006/06/08/8289.htmlStone Jiang Stone Jiang Thu, 08 Jun 2006 03:03:00 GMT http://www.shnenglu.com/ace/archive/2006/06/08/8289.html http://www.shnenglu.com/ace/comments/8289.html http://www.shnenglu.com/ace/archive/2006/06/08/8289.html#Feedback 0 http://www.shnenglu.com/ace/comments/commentRss/8289.html http://www.shnenglu.com/ace/services/trackbacks/8289.html E序员的八荣八?/p>
以塌实编码ؓ?以心气wؓ?/p>
以详l注释ؓ?以注释残~Zؓ?/p>
以勤于测试ؓ?以懒于测试ؓ?/p>
以简明文档ؓ?以冗余文档ؓ?/p>
以注重团队ؓ?以孤傲自大ؓ?/p>
以刻苦钻研ؓ?以敷衍了事ؓ?/p>
以善于ȝ 以不思进取ؓ?/p>
以质效ƈqؓ?以单取其一?/p>
]]> 关于用例的随W? http://www.shnenglu.com/ace/archive/2006/06/06/8214.htmlStone Jiang Stone Jiang Tue, 06 Jun 2006 07:56:00 GMT http://www.shnenglu.com/ace/archive/2006/06/06/8214.html http://www.shnenglu.com/ace/comments/8214.html http://www.shnenglu.com/ace/archive/2006/06/06/8214.html#Feedback 0 http://www.shnenglu.com/ace/comments/commentRss/8214.html http://www.shnenglu.com/ace/services/trackbacks/8214.html
http://www.shnenglu.com/ace/archive/2006/06/06/8214.html
q来因工作需要,我细阅读了一些与UML相关的书c?/p>
q里Q以水帐的方式Q作一L录?/p>
关于用例Q?/p>
1. 用例x需求,但需求ƈ不是用例?br /> 用例是描q讨论的pȝ(SuD)功能性需求的Q所以可以说用例是需求。但需求除了功能性需求,q有非功能性需求。所以,不能说需求就是用例?/p>
2. 用例不等于功?br /> 用例是描q系l功能的Q但用例不是功能。功能是pȝ要达到或满的目标,用例是用例的执行?Actor)与系l交互的操作序列。两者是有差异的?/p>
3. 用例是文本而不是图?br /> 用例是描q执行者与pȝ交互的操作序列,要体现它的执行者在与系l交互生的可观查的价倹{图形仅仅是用例的概qͼ只画图是不够的。由于这一点,用例建模是撰写文档的q程Q而不是画囄q程?/p>
4. 用例模型不仅仅是h加随?br /> 用例模型不仅是需求方面的工g(artifact)Q它q包括补充说?描述非功能需求的)Q词汇表Q愿景和业务规则。这些合在一h是需求分析的产物?/p>
5. 用例技术无d象技术,在通过用例发现Q描qͼ理需求的时候,用不到对象技术。但是,用例是面向对象的分析和设计的关键需求?/p>
6. 用例必须有一个主执行?(Primary actor) L行者确定了用例的名U。用例命令通常是以L行者视角的d语态的q宾l构的短语。因为只有这L短语才能充分的描q出pȝ的h倹{用例徏模的核心是要描q出pȝ的h倹{?/p>
7. 三种cd的执行?br /> 基本执行?(Primary actor) :q种用例通过与系l交互能辑ֈ目标 支持执行?(Supporting actor ) : 论的pȝQSuD)提供服务 q后执行?(Offstage actor ) :除了上述两种Q又对上qCU执行者与pȝ交互q程和结果感兴趣的h或物?/p>
]]> 介绍一些在C++用户l中常出现的~略?/title> http://www.shnenglu.com/ace/archive/2006/06/04/8144.htmlStone Jiang Stone Jiang Sun, 04 Jun 2006 04:18:00 GMT http://www.shnenglu.com/ace/archive/2006/06/04/8144.html http://www.shnenglu.com/ace/comments/8144.html http://www.shnenglu.com/ace/archive/2006/06/04/8144.html#Feedback 0 http://www.shnenglu.com/ace/comments/commentRss/8144.html http://www.shnenglu.com/ace/services/trackbacks/8144.html Here's a partial list of acronyms in alphabetical order:
AFAICS = As far as I can see
BTW = By the way
FWIW = For what it's worth
FYI = For your information
HAND = Have a nice day
IMHO = In my humble opinion (egoless)
IMAO = In my arrogant opinion (oodles of ego)
IMNSHO = In my not-so humble opinion (a lot of ego)
IMO = In my opinion (not much ego)
KUTGW = Keep up the good work
MYOB = Mind your own business
OO = Object-oriented
OTOH = On the other hand
PEBCAC = Problem exists between chair and computer
PEBCAK = Problem exists between chair and keyboard
PMFJI = Pardon me for jumping in
RTFM = Read the ___ manual
SO = Significant other (as in, "My SO and I went for a walk...")
SSO = Small String Optimization (where short strings don't use the heap)
YHBT = You have been trolled
YHL = You have lost
]]> 关于用例模式的一句话评论 http://www.shnenglu.com/ace/archive/2006/06/02/8070.htmlStone Jiang Stone Jiang Fri, 02 Jun 2006 01:33:00 GMT http://www.shnenglu.com/ace/archive/2006/06/02/8070.html http://www.shnenglu.com/ace/comments/8070.html http://www.shnenglu.com/ace/archive/2006/06/02/8070.html#Feedback 0 http://www.shnenglu.com/ace/comments/commentRss/8070.html http://www.shnenglu.com/ace/services/trackbacks/8070.html 书籍推荐 "Use Cases Patterns and Blueprints " ]]>static_cast<>揭密 (? http://www.shnenglu.com/ace/archive/2006/05/22/7510.htmlStone Jiang Stone Jiang Mon, 22 May 2006 13:18:00 GMT http://www.shnenglu.com/ace/archive/2006/05/22/7510.html http://www.shnenglu.com/ace/comments/7510.html http://www.shnenglu.com/ace/archive/2006/05/22/7510.html#Feedback 0 http://www.shnenglu.com/ace/comments/commentRss/7510.html http://www.shnenglu.com/ace/services/trackbacks/7510.html
static_cast<>揭密
作者:Sam NG
译者:刀?/a>
原文链接Q?a >What static_cast<> is actually doing 本文讨论static_cast<> ?reinterpret_cast<>?
介绍
大多E序员在学C++前都学过CQƈ且习惯于C风格Q类型)转换。当写C++Q程序)Ӟ有时候我们在使用static_cast<>和reinterpret_cast<>时可能会有点模糊。在本文中,我将说明static_cast<>实际上做了什么,q且指出一些将会导致错误的情况?br />泛型QGeneric TypesQ?/strong>
float f = 12.3;
float* pf = &f;
// static cast<>
// 成功~译, n = 12
int n = static_cast<int>(f);
// 错误,指向的类型是无关的(译注Q即指针变量pf是floatcdQ现在要被{换ؓintcdQ?
//int* pn = static_cast<int*>(pf);
//成功~译
void* pv = static_cast<void*>(pf);
//成功~译, 但是 *pn2是无意义的内存(rubbishQ?br />
int* pn2 = static_cast<int*>(pv);
// reinterpret_cast<>
//错误,~译器知道你应该调用static_cast<>
//int i = reinterpret_cast<int>(f);
//成功~译, 但是 *pn 实际上是无意义的内存,?*pn2一?br />
int* pi = reinterpret_cast<int*>(pf);
而言之,static_cast<> 尝试{换,举例来说Q如float-?integerQ而reinterpret_cast<>单改变编译器的意N新考虑那个对象作ؓ另一cd?br />指针cdQPointer TypesQ?/strong> 指针转换有点复杂Q我们将在本文的剩余部分使用下面的类Q?br />class CBaseX
{
public:
int x;
CBaseX() { x = 10; }
void foo() { printf("CBaseX::foo() x=%d\n", x); }
};
class CBaseY
{
public:
int y;
int* py;
CBaseY() { y = 20; py = &y; }
void bar() { printf("CBaseY::bar() y=%d, *py=%d\n", y, *py);
}
};
class CDerived : public CBaseX, public CBaseY
{
public:
int z;
};
情况1Q两个无关的cM间的转换
// Convert between CBaseX* and CBaseY*
// CBaseX* ?CBaseY*之间的{?br />
CBaseX* pX = new CBaseX();
// Error, types pointed to are unrelated
// 错误Q?cd指向是无关的
// CBaseY* pY1 = static_cast<CBaseY*>(pX);
// Compile OK, but pY2 is not CBaseX
// 成功~译, 但是 pY2 不是CBaseX
CBaseY* pY2 = reinterpret_cast<CBaseY*>(pX);
// System crash!!
// pȝ崩溃!!
// pY2->bar(); 正如我们在泛型例子中所认识到的Q如果你试转换一个对象到另一个无关的cstatic_cast<>失败,而reinterpret_cast<>L成功“欺骗”编译器Q那个对象就是那个无关类?br />情况2Q{换到相关的类 1. CDerived* pD = new CDerived();
2. printf("CDerived* pD = %x\n", (int)pD);
3.
4. // static_cast<> CDerived* -> CBaseY* -> CDerived*
//成功~译Q隐式static_cast<>转换
5. CBaseY* pY1 = pD;
6. printf("CBaseY* pY1 = %x\n", (int)pY1);
// 成功~译, 现在 pD1 = pD
7. CDerived* pD1 = static_cast<CDerived*>(pY1);
8. printf("CDerived* pD1 = %x\n", (int)pD1);
9.
10. // reinterpret_cast
// 成功~译, 但是 pY2 不是 CBaseY*
11. CBaseY* pY2 = reinterpret_cast<CBaseY*>(pD);
12. printf("CBaseY* pY2 = %x\n", (int)pY2);
13.
14. // 无关?static_cast<>
15. CBaseY* pY3 = new CBaseY();
16. printf("CBaseY* pY3 = %x\n", (int)pY3);
// 成功~译,管 pY3 只是一?"?CBaseY()"
17. CDerived* pD3 = static_cast<CDerived*>(pY3);
18. printf("CDerived* pD3 = %x\n", (int)pD3); ---------------------- 输出 ---------------------------
CDerived* pD = 392fb8
CBaseY* pY1 = 392fbc
CDerived* pD1 = 392fb8
CBaseY* pY2 = 392fb8
CBaseY* pY3 = 390ff0
CDerived* pD3 = 390fec 注意Q在CDerived*用隐?static_cast<>转换到CBaseY*Q第5行)Ӟl果是(指向QCDerived*Q的指针向后Q?偏移?Q个字节Q(译注Q?为intcd在内存中所占字节数Q。ؓ了知道static_cast<> 实际如何Q我们不得不要来看一下CDerived的内存布局?/p>
CDerived的内存布局QMemory LayoutQ?/strong> 如图所C,CDerived的内存布局包括两个对象QCBaseX ?CBaseYQ编译器也知道这一炏V因此,当你CDerived* 转换?CBaseY*Ӟ它给指针d4个字节,同时当你CBaseY*转换到CDerived*Ӟ它给指针减去4。然而,甚至它即便不是一个CDerived你也可以q样做?br />当然Q这个问题只在如果你做了多承时发生。在你将CDerived转换 ?CBaseX时static_cast<> ?reinterpret_cast<>是没有区别的?br />情况3Qvoid*之间的向前和向后转换 因ؓM指针可以被{换到void*Q而void*可以被向后{换到M指针Q对于static_cast<> ?reinterpret_cast<>转换都可以这样做Q,如果没有心处理的话错误可能发生?br />
CDerived* pD = new CDerived();
printf("CDerived* pD = %x\n", (int)pD);
CBaseY* pY = pD; // 成功~译, pY = pD + 4
printf("CBaseY* pY = %x\n", (int)pY);
void* pV1 = pY; //成功~译, pV1 = pY
printf("void* pV1 = %x\n", (int)pV1);
// pD2 = pY, 但是我们预期 pD2 = pY - 4
CDerived* pD2 = static_cast<CDerived*>(pV1);
printf("CDerived* pD2 = %x\n", (int)pD2);
// pȝ崩溃
// pD2->bar();
---------------------- 输出 ---------------------------
CDerived* pD = 392fb8
CBaseY* pY = 392fbc
void* pV1 = 392fbc
CDerived* pD2 = 392fbc 一旦我们已l{换指针ؓvoid*Q我们就不能L其转换回原cR在上面的例子中Q从一个void* q回CDerived*的唯一Ҏ是将其{换ؓCBaseY*然后再{换ؓCDerived*? 但是如果我们不能定它是CBaseY* q是 CDerived*Q这时我们不得不用dynamic_cast<> 或typeid[2]?br />注释Q?/strong> 1. dynamic_cast<>Q从另一斚w来说Q可以防止一个泛型CBaseY* 被{换到CDerived*?br />2. dynamic_cast<>需要类成ؓ多态,卛_括“虚”函敎ͼq因此而不能成为void*?br />参考: 1. [MSDN] C++ Language Reference -- Casting 2. Nishant Sivakumar, Casting Basics - Use C++ casts in your VC++.NET programs 3. Juan Soulie, C++ Language Tutorial: Type Casting
]]> C/C++ 内存理 Heap vs Stack http://www.shnenglu.com/ace/archive/2006/05/17/7313.htmlStone Jiang Stone Jiang Wed, 17 May 2006 09:09:00 GMT http://www.shnenglu.com/ace/archive/2006/05/17/7313.html http://www.shnenglu.com/ace/comments/7313.html http://www.shnenglu.com/ace/archive/2006/05/17/7313.html#Feedback 0 http://www.shnenglu.com/ace/comments/commentRss/7313.html http://www.shnenglu.com/ace/services/trackbacks/7313.html
转注: 今天有网友问到这个问?于是在网上搜索了一?转脓q此. 怼的太多了,出处不详.在此感谢原作者精彩讲?
一、预备知识—程序的内存分配 一个由c/C++~译的程序占用的内存分ؓ以下几个部分 1、栈区(stackQ— 由~译器自动分配释放 ,存放函数的参数|局部变量的值等。其操作方式cM于数据结构中的栈? 2、堆区(heapQ — 一般由E序员分配释放, 若程序员不释放,E序l束时可能由OS回收 。注意它与数据结构中的堆是两回事Q分配方式倒是cM于链表,呵呵? 3、全局区(静态区Q(staticQ—,全局变量和静态变量的存储是放在一块的Q初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在盔R的另一块区域。? E序l束后有pȝ释放 4、文字常量区 —常量字W串是攑֜q里的。 程序结束后ql释? 5、程序代码区—存攑ևC的二q制代码? 二、例子程? q是一个前辈写的,非常详细 // main.cpp int a = 0 ; 全局初始化区 char * p1; 全局未初始化区?br /> main() { int b; // 栈?/span>char s[] = " abc " ; // 栈?/span>char * p2; // 栈?/span>char * p3 = " 123456 " ; 123456 \ 0 " ;//在常量区Qp3在栈上。?/span>static int c = 0 Q?/span>// 全局Q静态)初始化区 p1 = ( char * )malloc( 10 ); p2 = ( char * )malloc( 20 ); // 分配得来?0?0字节的区域就在堆区。?/span>strcpy(p1, " 123456 " ); // 123456\0攑֜帔R区,~译器可能会它与p3所指向?123456"优化成一个地斏V?/span>} 三、堆和栈的理论知? 3.1甌方式 stack: ql自动分配。 例如,声明在函C一个局部变量 int b; pȝ自动在栈中ؓb开辟空? heap: 需要程序员自己甌Qƈ指明大小Q在c中malloc函数 如p1 = (char *)malloc(10); 在C++中用newq算W? 如p2 = (char *)malloc(10); 但是注意p1、p2本n是在栈中的? 3.2 甌后系l的响应 栈:只要栈的剩余I间大于所甌I间Q系l将为程序提供内存,否则报异常提示栈溢出? 堆:首先应该知道操作pȝ有一个记录空闲内存地址的链表,当系l收到程序的甌Ӟ 会遍历该链表Q寻扄一个空间大于所甌I间的堆l点Q然后将该结点从I闲l点链表中删除,q将该结点的I间分配l程序,另外Q对于大多数pȝQ会在这块内存空间中的首地址处记录本ơ分配的大小Q这P代码中的delete语句才能正确的释放本内存I间。另外,׃扑ֈ的堆l点的大不一定正好等于申L大小Q系l会自动的将多余的那部分重新攑օI闲链表中? 3.3甌大小的限? 栈:在Windows?栈是向低地址扩展的数据结构,是一块连l的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是pȝ预先规定好的Q在 WINDOWS下,栈的大小?MQ也有的说是1MQM是一个编译时q定的常数Q,如果甌的空间超q栈的剩余空间时Q将提示overflow。因此,能从栈获得的I间较小? 堆:堆是向高地址扩展的数据结构,是不q箋的内存区域。这是由于系l是用链表来存储的空闲内存地址的,自然是不q箋的,而链表的遍历方向是由低地址向高地址。堆的大受限于计算机系l中有效的虚拟内存。由此可见,堆获得的I间比较灉|Q也比较大? 3.4甌效率的比较: 栈由pȝ自动分配Q速度较快。但E序员是无法控制的? 堆是由new分配的内存,一般速度比较慢,而且Ҏ产生内存片,不过用v来最方便. 另外Q在WINDOWS下,最好的方式是用VirtualAlloc分配内存Q他不是在堆Q也不是在栈是直接在q程的地址I间中保留一快内存,虽然用v来最不方ѝ但是速度快,也最灉| 3.5堆和栈中的存储内? 栈: 在函数调用时Q第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句Q的地址Q然后是函数的各个参敎ͼ在大多数的C~译器中Q参数是由右往左入栈的Q然后是函数中的局部变量。注意静态变量是不入栈的? 当本ơ函数调用结束后Q局部变量先出栈Q然后是参数Q最后栈指针指向最开始存的地址Q也是dC的下一条指令,E序p点l运行? 堆:一般是在堆的头部用一个字节存攑֠的大。堆中的具体内容有程序员安排? 3.6存取效率的比? char s1[] = "aaaaaaaaaaaaaaa"; char *s2 = "bbbbbbbbbbbbbbbbb"; aaaaaaaaaaa是在q行时刻赋值的Q? 而bbbbbbbbbbb是在~译时就定的; 但是Q在以后的存取中Q在栈上的数l比指针所指向的字W串(例如?快? 比如Q?#include < stdio.h > ; void main() { char a = 1 ; char c[] = " 1234567890 " ; char * p = " 1234567890 " ; a = c[ 1 ]; a = p[ 1 ]; return ; }
对应的汇~代?10: a = c[1]; 00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh] 0040106A 88 4D FC mov byte ptr [ebp-4],cl 11: a = p[1]; 0040106D 8B 55 EC mov edx,dword ptr [ebp-14h] 00401070 8A 42 01 mov al,byte ptr [edx+1] 00401073 88 45 FC mov byte ptr [ebp-4],al W一U在d时直接就把字W串中的元素d寄存器cl中,而第二种则要先把指针D到edx中,在根据edxd字符Q显然慢了? 3.7结Q? 堆和栈的区别可以用如下的比喻来看出: 使用栈就象我们去饭馆里吃饭,只管点菜Q发出申P、付钱、和吃(使用Q,吃饱了就赎ͼ不必理会切菜、洗菜等准备工作和洗、刷锅等扫尾工作Q他的好处是快捷Q但是自由度? 使用堆就象是自己动手做喜Ƣ吃的菜_比较ȝQ但是比较符合自q口味Q而且自由度大? 堆和栈的区别主要分: 操作pȝ斚w的堆和栈Q如上面说的那些Q不多说了? q有是数据l构斚w的堆和栈Q这些都是不同的概念。这里的堆实际上指的是Q满_性质的)优先队列的一U数据结构,W?个元素有最高的优先权;栈实际上是满先进后出的性质的数学或数据l构? 虽然堆栈Q堆栈的说法是连h叫,但是他们q是有很大区别的Q连着叫只是由于历史的原因?br /> ]]> 避免依赖的消息处理方?(试译) http://www.shnenglu.com/ace/archive/2006/05/04/6629.htmlStone Jiang Stone Jiang Thu, 04 May 2006 12:52:00 GMT http://www.shnenglu.com/ace/archive/2006/05/04/6629.html http://www.shnenglu.com/ace/comments/6629.html http://www.shnenglu.com/ace/archive/2006/05/04/6629.html#Feedback 0 http://www.shnenglu.com/ace/comments/commentRss/6629.html http://www.shnenglu.com/ace/services/trackbacks/6629.html 避免依赖的消息处理方?br /> Anthony Williams url: http://www.ddj.com/dept/cpp/184429055 译? Stone Jiang 译者说明:本hq在学习英文的过E中Q有些句子很难译Q这里给出原文的链接Q欢q就其中译得不准的地方与我交换意见?br />
在您l护安全cd和避免集成电路般函数?你可以用C++的强大的力量q行消息传递?/p>
Anthony是Just Software Solution有限公司的一位Y件开发者和执行理者。可以通过anthony@justsoftwaresolutions.co.uk 与之联系?/p>
使用通用的消息传递方式传递数据在C++E序中很普遍。这U技术经常用于在U程间以及从/到GUIlg间传递数据。但是消息传递仍然很隑֮现得良好Q这是因为在常见的消息传递方式中Q暴露出了过多的藕合、缺类型安全和集成电\般的消息处理函数?/p>
在本文中Q我提出了一U技术,q种技术利用C++的强大力量来避免上述~陷——在消息传递中避免不适当的藕合,l护cd安全Q以及消除集成电路般的消息处理函? The only translation units that need to known the details of a message are those containning the source and handler functions for that specific message type.) 需要{换的单元Q即需要知道的消息详细内容是包含了特定消息的类型的源代码和处理函数?/p>
传统技?/h2>
大概应用得最为广泛的消息传递技术是使用一个带有特D成员来表示消息cd的结构体Q该消息cd是消息的标识。这U方式被q泛应用归咎于用了ZC的APIQ比如X11和Microsoft Windows。在q种Ҏ中,消息l构体中要么有一个通用的字体用于区别不同消息的意义Q这个字D可被所有消息重用,或者它是更大结构的W一个成员,它的cdq型代码来定。Windows API使用前面的技术,而X11使用后面的方法。无论用哪种方式Q处理消息的代码都须查类型编码,用以军_怎么处理该消息?/p>
q些技术的问题?~Zcd安全Q集成电路般的处理函敎ͼ需要管理类型编码来保消息唯一性的适当层次。特别的Q缺乏类型安全意味着使用之前Q用代码必L消息数据转换成适当的类型。这一步是极易出错的,其在当复制和粘贴代码时(q种非常的手D常发生在ؓ处理怼消息~写代码的时?Q编译器不会在这U错误给ZQ何警告?/p>
~Zcd安全q有一个额外的问题——即它不可能单有效的通过消息pȝ传递资源或变长的数据, q是因ؓ消息的发送方L不能知道何时Q或是否Q该消息已被处理q了?/p>
在这部分Q集成电路般的消息处理函数是必须用于定消息cd的物,通过已接收的消息来消息类型,然后得到如何处理它的方式。这U处理函数往往实现Z个很大的switch语句或是一串if eles if。一些框Ӟ如MFCQ提供一些宏来减pU问题的影响Q它q不能完全消除这个问题?/p>
最后的问题是管理类型代码。它必须要求接收消息代码清楚地知道是哪一个消息,以便于正的处理它。所以,cd代码需要在处理它的相关代码中确保唯一性。比如,在Windows API中,指定范围的消息类型在不同的应用程序中代表不同的意义,q且Q在同一个应qE序中,其它范围的消息类型在不同H口或GUIlg中代表不同的意义?通常,需要所有类型代码的列表Q该列表要求在给定的范围中保持唯一Q以便于查它们的唯一性。列表常常是以头文g的Ş式给出,头文件中定义了类型代码,包含在需要知道消息类型的所有地斏V这U方式容易导致应用程序不同部分之间的藕合,而这些部分之间却没有M关系。由于这U过度的藕,单的变更Dq多的重新编译?/p>
面向对象技?br />
对象技术的一个常见特征是所有相x息类z自一个通用的基cR该特征用编译器能认识的真实cd代替了显式的cd代码。不仅如此,它还有了一个重要的Q超C风格技术的优点——类型安全。它提供的通用基类的析构函数是虚函敎ͼ所以派生的消息c能自由地管理资源,如变长的数据Q这些数据可以在析构函数中释放。仅有的需求是接受消息的代码能正确地销毁消息对象,无论它们是否被处理?/p>
理cd代码现在被替换ؓ理cR这是一个更加简单的dQ由于可能的消息名字的范围是没有限制的,可能存在名字冲突Q但q一点可以通过名字I间来解冟?/p>
保持?/font>
最单的OOP技术就是用dynamic_cast查实际的消息cd代替查消息编码。然而,q依焉临着集成电\般地消息处理方式——现在通过包括dynamic_cast的比较链也优于通过cd~码字段比较链。如列表1:
void
handleMessage(Message
*
message)
{
if
(Message1
*
m
=
dynamic_cast
<
Message1
*>
(message))
{ handleMessage1(m); }
else
if
(Message2
*
m
=
dynamic_cast
<
Message2
*>
(message))
{ handleMessage2(m); }
//
}
[列表1]
一般而言Q由于仅仅是消息的源代码和接受消息的源代码需求知道相关的消息Q所以依赖得到降低。然后,集成电\般地处理函数现在需要知道消息的有关l节Q所以dynamic_cast需要消息的完整定义——如果分z另外的函数处理实际的消息QC风格技术的处理函数不需求知道消息的l节?/p>
双重分派
(Direct testing of a class's type using dynamic_cast is generally indicative of a design problem;)cȝcd用dynamic_cast的直试一般可表示计问?然而,单地把虚函数攑֜消息cM起不CQ何作用——它把消息处理与消息缠l在一Pq个消息使在W一个地方发送消息的目的p|?/p>
双重分派的关键点是,在消息类中的虚函数带有一个作为参数的处理器,然后在处理器上把自已作ؓ参数传递传递给另一个函数ƈ完成调用。因里的W二ơ到处理器的回调已经在实际的zcM完成Q所以真实的消息cd已经知道Q在处理器上能调用适当的函敎ͼ无论q个函数是通过重蝲的方式实现还是另外独立命名的函数来实?列表2)?/p>
class
Message {
public
:
virtual
void
dispatch(MessageHandler
*
handler)
=
0
; };
class
Message1:
public
Message {
void
dispatch(MessageHandler
*
handler) { handler
->
process(
this
); } };
class
Message2:
public
Message {
void
dispatch(MessageHandler
*
handler) { handler
->
process(
this
); } };
//
other message classes
class
MessageHandler {
void
process(Message1
*
);
void
process(Message2
*
);
//
overloads of process for other messages
};
[列表2]
依赖于重载的方式来区别不同的消息有利于大多数q——现在在每个消息cM虚函数的实现方式是相同的Q如果需要,可以通过宏来一致地包装Q或通过从一个消息到另一个消息中直接复制Q不会有出错的机会?/p>
双重分派存在一个缺点——高度藕合。由于通过重蝲方式在处理器cM的选择处理函数Q在消息cM虚函数的实现需要知道处理器cȝ定义的全部,因此必须注意到在pȝ中每个其它的cȝ名字。不光这些,如果要支持不同的处理器类Q处理函数必d通用的处理器的基cM声明函数Q所以每个处理器cddpȝ中注意到所有的消息cd(列表3)。增加或删除一个消息类型会引v应用E序大部分代码重新编译?/p>
class
MessageHandler
{
virtual
void
process(Message1
*
)
=
0
;
virtual
void
process(Message2
*
)
=
0
;
virtual
void
process(Message3
*
)
=
0
;
virtual
void
process(Message4
*
)
=
0
;
//
overloads of process for other messages
}
;
class
SpecificMessageHandler:
public
MessageHandler
{
void
process(Message1
*
);
void
process(Message2
*
);
void
process(Message3
*
);
void
process(Message4
*
);
//
overloads of process for other messages
}
;
class
OtherSpecificMessageHandler:
public
MessageHandler
{
void
process(Message1
*
);
void
process(Message2
*
);
void
process(Message3
*
);
void
process(Message4
*
);
//
overloads of process for other messages
}
;
[列表3]动态双重分z?br /> QIt was against this backdrop that I developed the technique I call "Dynamic Double Dispatch."Q我开发了一U技术,我称其ؓ“动态双重分z䏀,q种技术用于解决上q问题。尽有基本的双重分z技术,但选择的消息处理函C用的是在~译阶段定的重载技?管发现在正的消息处理器类中的实现是用虚函数机制),而动态双重分z是在运行时查在处理器上适当的处理函数的。结论是动态双重分z消除了双重分派的依赖问题。消息类型不在需要注意到其它的消息类型,q且处理器类仅需要注意到它的它要处理的消息?/p>
动态检查的关键ҎQ每一个消息类型有一个独立的基类——处理器cM适当的,设计为处理消息的基类z。然后在每个消息cM的分zև数能用dynamic_cast来检查从正派基类z的处理器c,因而实C正确的处理函数?列表4)
class
MessageHandlerBase {};
class
Message1HandlerBase:
public
virtual
MessageHandlerBase {
virtual
void
process(Message1
*
)
=
0
; };
class
Message1 {
void
dispatch(MessageHandlerBase
*
handler) { dynamic_cast
<
Message1HandlerBase
&>
(
*
handler).process(
this
); } };
class
Message2HandlerBase:
public
virtual
MessageHandlerBase {
virtual
void
process(Message2
*
)
=
0
; };
class
Message2:
public
MessageBase {
void
dispatch(MessageHandlerBase
*
handler) { dynamic_cast
<
Message2HandlerBase
&>
(
*
handler).process(
this
); } };
//
class
SpecificMessageHandler:
public
Message1HandlerBase,
public
Message2HandlerBase {
void
process(Message1
*
);
void
process(Message2
*
); };
class
OtherSpecificMessageHandler:
public
Message3HandlerBase,
public
Message4HandlerBase {
void
process(Message3
*
);
void
process(Message4
*
); };
[列表4]
(Of course, having a completely separate handler base class for each message type would add excessive complication, as the dispatch function for each message type would now be specific to that message type, and the base classes would have to be written separately, despite being fundamentally the same, except for the message type they referenced.) 诚然Qؓ每个消息cd分别~写的处理器基类增加过多的复杂性,同样圎ͼ每个消息cd各自的分zև数现在需要特别指定,基类也需求分别编?然后除了它们引用的消息类型外基础是相同的。消除这U重复的关键是基类成ؓ模板Q用消息cd作ؓ模板参数——分zև数引用到模板的实现好于指定类型;L列表5?/p>
template
<
typename MessageType
>
class
MessageHandler:
public
virtual
MessageHandlerBase {
virtual
void
process(MessageType
*
)
=
0
; };
class
Message1 {
void
dispatch(MessageHandlerBase
*
handler) { dynamic_cast
<
MessageHandler
<
Message1
>&>
(
*
handler).process(
this
); } };
class
SpecificMessageHandler:
public
MessageHandler
<
Message1
>
,
public
MessageHandler
<
Message2
>
{
void
process(Message1
*
);
void
process(Message2
*
); };
[列表5] Z化原因,在消息类中的分派函数几乎相同Q但也不是完全相同——它们必L的指定属于它们的指定消息类Q以便于转换为适当的处理器基类。像软g中许多事情一Pq个问题可以增加一个额外的层来解决——分zև数可以委托给单个模板函数Q这个模板函C用模板参数类型来定消息cd和把处理器{换到适当的类型上?列表6)
class
Message {
protected
: template
<
typename MessageType
>
void
dynamicDispatch(MessageHandlerBase
*
handler,MessageType
*
self) { dynamic_cast
<
MessageHandler
<
MessageType
>&>
(
*
handler).process(self); } };
class
Message1:
public
MessageBase {
void
dispatch(MessageHandlerBase
*
handler) { dynamicDispatch(handler,
this
); } };
[列表6]
通过q一步抽象在消息对象中分zև数的不同之处,我们把工作集中到一个地方——模板函数的定义Q它提供了ؓ修改行ؓ的单一炏V在消息cM剩下的分zև数都是相同的Q这以把它们简化到隐藏l节的宏中或在消息类之间中逐字复制?/p>
未处理的消息
q今为止Q我们展C的 dynamicDispach模板函数的代码假定处理的cL从适当的SpecificMessageHandler是派生的Q如是不是这P dynamic_cast抛出std::bad_cast异常。有时这p够了Q但是有的时候,有更适当的行为——也许更好的做法是抛弃消息,q不能被接受消息的代理处理或调用catch-all处理器。D例来_dynamicDispatch 函数能被调整Q用Z指针的{换代替基于引用的转换Q所以结果值可以与NULLq行试?/p>
~点(Trade-Off)在哪里?
有如此多的优点,一定存在它的缺点,那它的缺点在哪里呢?在这里,有两个缺炏V第一个是Q额外的动态{换,两个虚函数调用会影响性能。如果性能上是一个问题,q就是一个疑问,但是Q在很多情况下,花销在这里的额外的时间是不值得x的。可以用相应的工具来签定到底哪里才是真正的性能瓉所在?/p>
W二个缺Ҏ:需要ؓ每个消息处理从指定的基类z消息处理器。因为处理新的消息类型需要修改两个地方——适当的基cd表入口和处理函数Q所以这可能成ؓ错误的来源,遗失处理函数Ҏ被发玎ͼ因ؓq是全局点,但是遗失基类在代码运行时只生不易查觉的~陷。因为没有处理函数的时候仅仅是不调用它。这些错误在单元试的时候是很容易被抓出来的Q所以所实话Q这些不便之处都成不了大问题?/p>
]]>socket~程QSO_REUSEADDR例解 (? http://www.shnenglu.com/ace/archive/2006/04/29/6446.htmlStone Jiang Stone Jiang Sat, 29 Apr 2006 01:40:00 GMT http://www.shnenglu.com/ace/archive/2006/04/29/6446.html http://www.shnenglu.com/ace/comments/6446.html http://www.shnenglu.com/ace/archive/2006/04/29/6446.html#Feedback 0 http://www.shnenglu.com/ace/comments/commentRss/6446.html http://www.shnenglu.com/ace/services/trackbacks/6446.html 阅读全文 ]]> 谈谈C++l承中的重蝲Q覆盖和隐藏 (? http://www.shnenglu.com/ace/archive/2006/04/25/6243.htmlStone Jiang Stone Jiang Tue, 25 Apr 2006 05:29:00 GMT http://www.shnenglu.com/ace/archive/2006/04/25/6243.html http://www.shnenglu.com/ace/comments/6243.html http://www.shnenglu.com/ace/archive/2006/04/25/6243.html#Feedback 0 http://www.shnenglu.com/ace/comments/commentRss/6243.html http://www.shnenglu.com/ace/services/trackbacks/6243.html
写正题之前,先给出几个关键字的中英文对照Q重?overload)Q覆?override),隐藏(hide)。在早期的C++书籍中,可能译的h不熟悉专业用语(也不能怪他们,他们不是搞计机~程的,他们是英语专业的Q,常常把重?overload)和覆?override)搞错Q?/p>
我们先来看一些代码及其编译结果?/p>
实例一Q?br /> #include "stdafx.h" #include <iostream.h>
class CB { public: void f(int) { cout << "CB::f(int)" << endl; }
};
class CD : public CB { public: void f(int,int) { cout << "CD::f(int,int)" << endl; }
void test() { f(1); } };
int main(int argc, char* argv[]) { return 0; } ~译了一?br />error C2660: 'f' : function does not take 1 parameters
l论Q在cCDq个域中Q没有f(int)q样的函敎ͼ基类中的void f(int)?font color="#ff0000">隐藏
如果把派生CD中成员函数void f(int,int)的声明改成和基类中一P即f(int)Q基cM的void f(int)q是一栯覆盖Q此时编译不会出错,在函Ctest调用的是CD中的f(int)
所以,?font color="#ff0000">基类?/font>的某些函敎ͼ如果没有 virtral 关键字,函数名是f( 参数是什么我们不?Q那么如果在zcCD?font color="#ff0000">也声明了某个f成员函数Q那么在cCD域中Q?font color="#ff0000">基类中所有的那些f都被隐藏?/font> 如果你比较心急,想知道什么是隐藏Q看文章最后的单说明,不过我徏议你q是一步一步看下去?/p>
我们刚才说的是没有virtual的情况,如果有virtual的情况呢Q? 实例二:
#include "stdafx.h" #include <iostream.h>
class CB { public: virtual void f(int) { cout << "CB::f(int)" << endl; }
};
class CD : public CB { public: void f(int) { cout << "CD::f(int)" << endl; }
};
int main(int argc, char* argv[]) { return 0; }
q么写当然是没问题了Q在q里我不多费口舌了,q是很简单的Q多态,虚函敎ͼ然后什么指向基cȝ指针指向zcd象阿Q通过引用调用虚函数阿什么的Q属性多的很咯,什么?Q你不明白?Q随便找本C++的书Q对会讲多态和虚函数机制的哦!Q?br /> q种情况我们?font color="#ff0000">覆盖(override)Q?/font>覆盖指的是派生类的虚拟函数覆盖了基类的同名且参数相同的函敎ͼ 在这里,我要的是Q这U覆盖,要满两个条?br /> (a) 有virtual关键?/font>Q在基类中函数声明的时候加上就可以?br /> (b) 基类CB中的函数和派生类CD中的函数要一模一?/font>Q什么叫一模一P函数名,参数Q返回类型三个条?/font>?br /> 有h可能会对(b)中的说法质疑Q说q回cd也要一PQ?br /> 是,覆盖的话必须一P我试了试Q如果在基类?把f的声明改成virtual int f(int)Q编译出错了 error C2555: 'CD::f' : overriding virtual function differs from 'CB::f' only by return type or calling convention 所以,覆盖的话Q必要满上述?a)(b)条g
那么如果基类CB中的函数f有关键字virtual Q但是参数和zcCD中的函数f参数不一样呢Q?br />实例? #include "stdafx.h" #include <iostream.h>
class CB { public: virtual void f(int) { cout << "CB::f(int)" << endl; }
} ;
class CD : public CB { public: void f(intQint) { cout << "CD::f(intQint)" << endl; }
void test() { f(1); } } ;
int main(int argc, char* argv[]) { return 0; }
~译出错了, error C2660: 'f' : function does not take 1 parameters 咦?Q好面熟的错Q?对,和实例一中的情况一样哦Q结Z是基cM的函数被隐藏了?/p>
通过上面三个例子Q得Z个简单的l论 如果基类中的函数和派生类中的两个名字一L函数f 满下面的两个条?br />(a)在基cM函数声明的时候有virtual关键?br />(b)基类CB中的函数和派生类CD中的函数一模一P函数名,参数Q返回类型都一栗?br />那么q就是叫?font color="#ff0000">覆盖(override)Q?/font>q也是虚函敎ͼ多态的性质
那么其他的情况呢Q?只要名字一P不满上面覆盖的条gQ就?font color="#ff0000">隐藏 了?/font>
下面我要讲最关键的地方了 Q好多h认ؓQ基cCB中的f(int)会承下来和CD中的f(int,int)在派生类CD中构成重载,像实例一中想像的那样?br /> 对吗Q我们先看重载的定义 重蝲(overload): 必须在一个域?函数名称相同但是函数参数不同,重蝲的作用就是同一个函数有不同的行?因此不是在一个域中的函数是无法构成重载的,q个是重载的重要特征 必须在一个域?/font>Q而承明显是在两个类中了哦,所以上面的x是不成立的,我们试的结构也是这PzcM的f(int,int)把基cM的f(int)隐藏?br /> 所以,相同的函数名的函敎ͼ在基cdzcM的关pd能是覆盖或者隐藏?/font>
在文章中Q我把重载和覆盖的定义都l了出来了,但是一直没有给隐藏的定义,在最后,我把他给出来Q这D话是网上google来的Q比较长Q你可以单的理解成,在派生类域中Q看不到基类中的那个同名函数了,或者说Q是q没有承下来给你用Q呵呵,如实例一 那样?br />
隐藏(hide): 指的是派生类的成员函数隐藏了基类函数的成员函?隐藏一词可以这么理?在调用一个类的成员函数的时?~译器会沿着cȝl承N的向上查扑և数的定义,如果扑ֈ了那么就停止查找?所以如果一个派生类和一个基c都有同一个同?暂且不论参数是否相同)的函?而编译器最l选择了在zcM的函?那么我们pq个zcȝ成员函数"隐藏"了基cȝ成员函数,也就是说它阻止了~译器l向上查扑և数的定义
]]> STL中map与hash_map容器的选择 (? http://www.shnenglu.com/ace/archive/2006/04/25/6223.htmlStone Jiang Stone Jiang Tue, 25 Apr 2006 01:25:00 GMT http://www.shnenglu.com/ace/archive/2006/04/25/6223.html http://www.shnenglu.com/ace/comments/6223.html http://www.shnenglu.com/ace/archive/2006/04/25/6223.html#Feedback 0 http://www.shnenglu.com/ace/comments/commentRss/6223.html http://www.shnenglu.com/ace/services/trackbacks/6223.html
STL中map与hash_map容器的选择
]]> 单讲解ACE_SOCK Wrapper Class的?原创) http://www.shnenglu.com/ace/archive/2006/04/20/5987.htmlStone Jiang Stone Jiang Thu, 20 Apr 2006 15:50:00 GMT http://www.shnenglu.com/ace/archive/2006/04/20/5987.html http://www.shnenglu.com/ace/comments/5987.html http://www.shnenglu.com/ace/archive/2006/04/20/5987.html#Feedback 0 http://www.shnenglu.com/ace/comments/commentRss/5987.html http://www.shnenglu.com/ace/services/trackbacks/5987.html 单讲解ACE_SOCK Wrapper Class的?/h1>
Stone Jianghttp://www.shnenglu.com/ace
我们先来看一个场?
您去一安馆吃?q家馆位置在水木清华?3P您得事先知道馆的位|,从门q入Q如果你想破墙而入那是不允可的。当你进门后Q餐馆会有一位领位员招呼你,领位员会安排一个服务员Z提供服务的,你可以向服务员点菜,或听取服务员的推荐。用后你离开馆?br />
利用ACE SOCK~程Q与上馆子极其相伹{我们来作一个对比?br />
馆的位|,嗯,计算ZQ我们是IP地址Q水木清华我们对应的?smth.org,它的门牌号呢Q对应的是我们的端口地址Q在ACE中,我们用ACE_INET_Addr来表C?br />
卻I
ACE_INET_Addr peer_addr;
peer_addr;.set(23,"smth.org");
我们也可以直接通过它的带参数的构造函数来声明和初始化Q?br />
ACE_INET_Addr peer_addr(23,"smth.org")
馆的领位员相当?ACE_SOCK_Acceptor,它被动的站在站口{着客户的到来,您作为客P是主动端QACE_SOCK_Connector则是您将在代码中看到的?br />
ACE面向q接的网l编E,有三个主要的角色
d?被动端和数据交流的通道Q即
ACE_SOCK_Acceptor, ACE_SOCK_Connector和ACE_SOCK_Stream
接收和发送数据,则通过 ACE_SOCK_Stream::recv(...)和send(...)完成Q本例演CZ接收时的调用?br />
完成数据交互之后QACE_SOCK_Stream::close()完成断开q接操作?q相当于买单Ch?br />
注:smth.org:23是水木清华Telnet服务Q您q可以通过
telnet smth.org来访问?br />
下面是完整代码示?VC 7.1下调试通过// @file: mybrowser.cpp // Main function // @auth: Stone Jiang <2005119@gmail.com> // @date: 2006-4-20 #include " ace /Log_Msg.h" #include " ace /SOCK_Connector.h" #include " ace /SOCK_Stream.h" #include " ace /INET_Addr.h" int ACE_TMAIN( int argc, ACE_TCHAR * argv[]) { ACE_DEBUG((LM_DEBUG, " start here\n " )); const char * server_hostname = " smth.org " ; ACE_SOCK_Connector connector; ACE_SOCK_Stream peer; ACE_INET_Addr peer_addr; char buf[ 64 ] = { 0 }; if (peer_addr. set ( 23 ,server_hostname) == - 1 ) { ACE_ERROR_RETURN((LM_DEBUG, " (%P|%t) %p\n " , " Set server host " ), - 1 ); } else if (connector.connect(peer,peer_addr) == - 1 ) { ACE_ERROR_RETURN((LM_DEBUG, " (%P|%t) %p\n " , " Connection " ), - 1 ); } ACE_DEBUG((LM_DEBUG, " 建立q接成功 \n " )); const int s = 64 * 10 ; int m = 0 ; for (ssize_t n; (n = peer.recv(buf, sizeof buf)) > 0 ;) { ace ::write_n(ACE_STDOUT,buf,n); m += n; if ( m > s) { break ; } } peer.close(); return 0 ; } ]]> 巧用虚友元函?原创) http://www.shnenglu.com/ace/archive/2006/04/17/5796.htmlStone Jiang Stone Jiang Mon, 17 Apr 2006 14:12:00 GMT http://www.shnenglu.com/ace/archive/2006/04/17/5796.html http://www.shnenglu.com/ace/comments/5796.html http://www.shnenglu.com/ace/archive/2006/04/17/5796.html#Feedback 3 http://www.shnenglu.com/ace/comments/commentRss/5796.html http://www.shnenglu.com/ace/services/trackbacks/5796.html 父类的友元不会自动成为子cȝ友元Q而且友元会破坏封装;C++的语方不允许Q非成员Q友元函Cؓ虚函数?br />但是Q某些时候,必须通过友元才能实现一些操作符重蝲Q如operator<<()Q如果ؓ每个子类都实现operator<<()倒是一个可行的ҎQ但是显得很啰嗦?br /> 如果能把友元定义函数Q则子类可以l承该友元的接口而无需重复声明友好那该多好啊? 本文则通过一U变通的Ҏ巧妙辑ֈ虚函数的效果?br /> //基类 Base.
#pragma once #include
<
iostream
>
using
namespace
std;
class
Base
{
public
: Base(
void
);
~
Base(
void
);
public
:
virtual
void
print(ostream
&
output)
=
0
; friend ostream
&
operator
<<
(ostream
&
output,Base
&
obj);
private
:
char
*
name_;
int
age_; }
;
基类的实?base.cpp#include " StdAfx.h " #include " .\base.h " Base::Base(void ) { name_ = " This is data1 " ; age_ = 18 ; } Base::~ Base( void ) { } void Base::print(ostream & output) { output << " name = " << name_ << endl; output << " age = " << age_ << endl; } ostream& operator << (ostream & output,Base & obj) { obj.print(output); return output; } zcȝ Derived.h#pragma once #include " Base.h " class Derived : public Base { public : Derived( int score = 80 ); ~ Derived( void ); virtual void print(ostream & output); private : int score_; } ; zcȝ实现 Derived.cpp#include " StdAfx.h " #include " .\derived.h " Derived::Derived(int score):score_(score) { } Derived::~ Derived( void ) { } void Derived::print(ostream & output) { Base::print(output); output << " score = " << score_ << endl; } ȝ序main.cpp// Test_VirtualFirendFunction.cpp : Defines the entry point for the console application. // #include " stdafx.h " #include < iostream > #include " Derived.h " using namespace std; int _tmain( int argc, _TCHAR * argv[]) { Derived d; Derived d2( 90 ); cout << d << endl << d2 << endl; return 0 ; } 屏幕输入l果name = This is data1 age = 18 score = 80 name = This is data1 age = 18 score = 90 l果Q?br />M从BasezcȝQ都可以利用cout<<obj的机刉过进行输出?br /> 同样道理Q也可以利用此方法实现ACE_InputCDR / ACE_OutputCDR对网l操作序列化操作?br />(本文也是回答某网友关于派生类不能重蝲的问题的回复)
]]> C++风格的类型{换的用法 (? http://www.shnenglu.com/ace/archive/2006/04/16/5641.htmlStone Jiang Stone Jiang Sun, 16 Apr 2006 06:21:00 GMT http://www.shnenglu.com/ace/archive/2006/04/16/5641.html http://www.shnenglu.com/ace/comments/5641.html http://www.shnenglu.com/ace/archive/2006/04/16/5641.html#Feedback 1 http://www.shnenglu.com/ace/comments/commentRss/5641.html http://www.shnenglu.com/ace/services/trackbacks/5641.html
C++风格的类型{换的用法 q是More Effecitve C++里的W二条对cd转换讲的很好Q也很基好懂?br />Item M2Q尽量用C++风格的类型{?br />仔细xC卑贱的类型{换功能(castQ,其在E序设计中的Cpgoto语句一样o人鄙视。但是它q不是无法o人忍受,因ؓ当在某些紧要的关_cd转换q是必需的,q时它是一个必需品?br />不过C风格的类型{换ƈ不代表所有的cd转换功能?br />一
来它们过于粗鲁,能允怽在Q何类型之间进行{换。不q如果要q行更精的cd转换Q这会是一个优炏V在q些cd转换中存在着巨大的不同,例如把一个指?
const对象的指针(pointer-to-const-objectQ{换成指向非const对象的指针(pointer-to-non
-const -objectQ?即一个仅仅去除const的类型{?Q把一个指向基cȝ指针转换成指向子cȝ指针Q即完全改变对象cdQ?
传统的C风格的类型{换不对上qCU{换进行区分。(q一点也不o人惊Ӟ因ؓC风格的类型{换是为C语言设计的,而不是ؓC++语言设计的)?br />?
来C风格的类型{换在E序语句中难以识别。在语法上,cd转换由圆括号和标识符l成Q而这些可以用在CQ+中的M地方。这使得回答象这样一个最基本的有
关类型{换的问题变得很困难:“在q个E序中是否用了cd转换Q”。这是因Zh工阅d可能忽略了类型{换的语句Q而利用象grep的工L序也不能?
语句构成上区分出它们来?br />C++通过引进四个新的cd转换操作W克服了C风格cd转换的缺点,q四个操作符?
static_cast, const_cast, dynamic_cast, 和reinterpret_cast?
在大多数情况下,对于q些操作W你只需要知道原来你习惯于这样写Q?br />(type) expression 而现在你d该这样写Q?br />static_cast
<
type
>
(expression) 例如Q假设你x一个int转换成doubleQ以便让包含intcd变量的表辑ּ产生出QҎ值的l果。如果用C风格的类型{换,你能q样写: int firstNumber, secondNumber; double result = ((double)firstNumber)/secondNumberQ?br />如果用上q新的类型{换方法,你应该这样写Q?br />double result = static_cast
<
double
>
(firstNumber)/secondNumber; q样的类型{换不论是对h工还是对E序都很Ҏ识别?br />static_cast
在功能上基本上与C风格的类型{换一样强大,含义也一栗它也有功能上限制。例如,你不能用static_cast象用C风格的类型{换一h
struct转换成intcd或者把doublecd转换成指针类型,另外Qstatic_cast不能从表辑ּ中去除const属性,因ؓ
另一个新的类型{换操作符const_cast有这L功能?br />其它新的C++cd转换操作W被用在需要更多限制的地方。const_cast用于
cd转换掉表辑ּ的const或volatileness属性。通过使用const_castQ你向h们和~译器强调你通过cd转换惛_的只是改变一些东
西的 constness或者volatileness属性。这个含义被~译器所U束。如果你试图使用const_cast来完成修?
constness 或者volatileness属性之外的事情Q你的类型{换将被拒l。下面是一些例子: class Widget { }; class SpecialWidget: public Widget { }; void update(SpecialWidget *psw); SpecialWidget sw; // sw 是一个非const 对象?br />const SpecialWidget& csw = sw; // csw 是sw的一个引?br />// 它是一个const 对象 update(
&csw
); // 错误!不能传递一个const SpecialWidget* 变量 // l一个处理SpecialWidget*cd变量的函?br />update(const_cast
<
SpecialWidget
*
>
(
&csw
)); // 正确Qcsw的const被显C地转换掉( // csw和sw两个变量值在update //函数中能被更斎ͼ update((SpecialWidget*)
&csw
); // 同上Q但用了一个更难识?br />//的C风格的类型{?br />Widget *pw = new SpecialWidget; update(pw); // 错误Qpw的类型是Widget*Q但?br />// update函数处理的是SpecialWidget*cd update(const_cast
<
SpecialWidget
*
>
(pw)); // 错误Qconst_cast仅能被用在媄?br />// constness or volatileness的地方上? // 不能用在向承子c进行类型{换?br />到目前ؓ止,const_cast最普通的用途就是{换掉对象的const属性?br />W?
二种Ҏ的类型{换符是dynamic_castQ它被用于安全地沿着cȝl承关系向下q行cd转换。这是_你能用dynamic_cast把指向基
cȝ指针或引用{换成指向其派生类或其兄弟cȝ指针或引用,而且你能知道转换是否成功。失败的转换返回空指针Q当Ҏ针进行类型{换时Q或者抛出异?
Q当对引用进行类型{换时Q: Widget *pw; update(dynamic_cast
<
SpecialWidget
*
>
(pw)); // 正确Q传递给update函数一个指?br />// 是指向变量类型ؓSpecialWidget的pw的指?br />// 如果pw实指向一个对? // 否则传递过ȝɽI指针?br />void updateViaRef(SpecialWidget& rsw); updateViaRef(dynamic_cast
<
SpecialWidget
&
>
(*pw)); //正确。传递给updateViaRef函数 // SpecialWidget pw 指针Q如果pw // 实指向了某个对?br />// 否则抛出异?br />dynamic_casts在帮助你览l承层次上是有限制的。它不能被用于缺乏虚函数的类型上Q参见条ƾM24Q,也不能用它来转换掉constnessQ?br />int firstNumber, secondNumber; double result = dynamic_cast
<
double
>
(firstNumber)/secondNumber; // 错误Q没有承关p?br />const SpecialWidget sw; update(dynamic_cast
<
SpecialWidget
*
>
(
&sw
)); // 错误! dynamic_cast不能转换 // 掉const?br />如你惛_没有l承关系的类型中q行转换Q你可能惛_static_cast。如果是Z去除constQ你d用const_cast?br />q四个类型{换符中的最后一个是reinterpret_cast。用这个操作符的类型{换,其的转换l果几乎都是执行期定义(implementation-definedQ。因此,使用reinterpret_casts的代码很隄植?br />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ɾ~译Kq?/span>
]]> 今天喜得两本?需要的La http://www.shnenglu.com/ace/archive/2006/04/14/5514.htmlStone Jiang Stone Jiang Fri, 14 Apr 2006 02:14:00 GMT http://www.shnenglu.com/ace/archive/2006/04/14/5514.html http://www.shnenglu.com/ace/comments/5514.html http://www.shnenglu.com/ace/archive/2006/04/14/5514.html#Feedback 5 http://www.shnenglu.com/ace/comments/commentRss/5514.html http://www.shnenglu.com/ace/services/trackbacks/5514.html C++ Coding Standards: 101 Rules, Guidelines, and Best Practices By Herb Sutter , Andrei Alexandrescu q本书得?005 Jolt大奖 2. The Art or Unix Programming q是lxxx和yyyy以来的最优秀的Unixȝ. ]]>通过模板实现"多态?,避开l承带来的性能开销之讨? http://www.shnenglu.com/ace/archive/2006/04/14/5506.htmlStone Jiang Stone Jiang Fri, 14 Apr 2006 01:29:00 GMT http://www.shnenglu.com/ace/archive/2006/04/14/5506.html http://www.shnenglu.com/ace/comments/5506.html http://www.shnenglu.com/ace/archive/2006/04/14/5506.html#Feedback 0 http://www.shnenglu.com/ace/comments/commentRss/5506.html http://www.shnenglu.com/ace/services/trackbacks/5506.html 多态生其实q可以通过cȝ聚合或组合的方式来达?wbr>,从而还可以避免l承或多l承,
代码如下 (未在开发环境中调试)
#include < stdio.h > template < class T > class A { public : void print() { base_.b(); } typename T base_; }; class B { public : void b() { printf( " Class B---------------------\n " ); } }; class C { public : void b() { printf( " Class C---------------------\n " ); } }; int main( int , char * []) { A < B > c; c.print(); A < C > c2; c2.print(); return 0 ; }
]]> 通过模板实现"多态?,避开l承带来的性能开销之讨?/title> http://www.shnenglu.com/ace/archive/2006/04/13/5478.htmlStone Jiang Stone Jiang Thu, 13 Apr 2006 10:21:00 GMT http://www.shnenglu.com/ace/archive/2006/04/13/5478.html http://www.shnenglu.com/ace/comments/5478.html http://www.shnenglu.com/ace/archive/2006/04/13/5478.html#Feedback 0 http://www.shnenglu.com/ace/comments/commentRss/5478.html http://www.shnenglu.com/ace/services/trackbacks/5478.html q里是"多态性"的一U实现方?/div>
#include < stdio.h > template < class BASE > class A : public BASE { public : void print() { BASE::b(); } }; class B { public : void b() { printf( " Class B---------------------\n " ); } }; class C { public : void b() { printf( " Class C---------------------\n " ); } }; int main( int , char * []) { A < B > c; c.print(); A < C > c2; c2.print(); return 0 ; }
管General Programming 与Object-Oriend Programming没有什么优劣之?如做乘法和做加法没有?wbr>坏之分一P
但这里,我还是想问一下,q里有模板有什么具体的好处Q?/div>
与之{效的我可以通过从基cL生的方式Q实现同L效果Q但众所周知Q承伴随着是virtual table和性能下降Q这里,用这U方法显然可以避开上述问题Q?/wbr>
q只是我的认知能力,Z抛砖引玉的目的,希望大家能多发表Ҏ?wbr>Q这q有什么益处呢Q?/wbr>
]]>
C++~码不规范出现的错误一例的解析 http://www.shnenglu.com/ace/archive/2006/04/11/5292.htmlStone Jiang Stone Jiang Tue, 11 Apr 2006 07:29:00 GMT http://www.shnenglu.com/ace/archive/2006/04/11/5292.html http://www.shnenglu.com/ace/comments/5292.html http://www.shnenglu.com/ace/archive/2006/04/11/5292.html#Feedback 0 http://www.shnenglu.com/ace/comments/commentRss/5292.html http://www.shnenglu.com/ace/services/trackbacks/5292.html
在Huihoo的ACE论坛中,有一|友问到Z么ACE_Time_Value的秒数在Debug版本一U,?br />在Release版本上“正常”。经q对其代码的复读以及对ACE的跟t,发现原来是编码不规范?br />下的一个很严重的错误造成的。本文就讨论q一例子?br /> 以下引用
1 /* 2 我写了个从年月日时分U数值得到ACE_Time_Valuel果的函? 3 */ 4 long s_get_ace_datetime(ACE_Time_Value & ace_datetime, 5 int year, 6 int month, 7 int day, 8 int hour, 9 int min, 10 int sec) 11 { 12 if (year < 1970 || year > 2038 || month < 1 || month > 12 || day < 1 || day > 31 || 13 hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || sec > 59 ) 14 ACE_ERROR_RETURN((LM_ERROR, 15 ACE_TEXT( " %I(日期旉参数溢出合理的习惯日期时间范?970.1.2-2038.1.18)n " )), - 1 ); 16 timespec_t spec_t; 17 tm time_tm; 18 time_tm.tm_year = year - 1900 ; 19 time_tm.tm_mon = month - 1 ; 20 time_tm.tm_mday = day; 21 time_tm.tm_hour = hour; 22 time_tm.tm_min = min; 23 #if defined (ACE_NDEBUG) 24 time_tm.tm_sec = sec; 25 #else 26 time_tm.tm_sec = sec + 1 ; // 奇?当由各部分数量构造ACE_Time_Value?debug~译?U的数量L自动?,在此要补? 27 #endif 28 spec_t.tv_sec = mktime( & time_tm); 29 if (spec_t.tv_sec < 0 ) 30 ACE_ERROR_RETURN((LM_ERROR,ACE_TEXT( " %I(日期旉转化错误,得到<0的time_t,日期范围?970.1.2-2038.1.18)n " )), - 1 ); 31 ace_datetime. set (spec_t); 32 return 0 ; 33 } 34 /* 35 我在VC++7.1上分别编译了Debug版本和Release版本,time_tm.tm_sec竟然会有一U的差别,莫名其妙地媄响了我的目. 36 哪位高手知道Z? 37 另外ACE_Time_Value的范围太?ACE中是否有大日期时间范围的其它cd? 38 */
以下是我的回?
你这个问题还真有?我跟t了ACE相关代码后才发现,问题原来出在你写的函C,病因?使用未完全初始化的结构体变量 timespec_t spec_t; 后面加上语句 memset(
&spec_t
,0,sizeof(timespec_t)); 卛_ 局部变量 spec_t 在debug?各字D均被初始化?xCCCCCCCC,它是一个负?br /> 在下面的操作?只修改了tv_sec,而tv_nsec 仍ؓ一个负?br /> spec_t.tv_sec=mktime(
&time_tm
); ACE_Time_Value::normalize()默默Cؓ你作了规格化处理Q就替你减去了一U钟?br />
原代码更严重的错误在于: 原以?Release版本是“正常”的Q其实不Ӟ而是Release隐藏了更严重的错误?br />严重是因为它表现出错误的时候很随机Q一旦品发布,很难发现?br />
//
对象(l构?timespec有两个公有属?/span>
typedef
struct
timespec
{ time_t tv_sec;
//
Seconds
long
tv_nsec;
//
Nanoseconds, 十亿分之一U?/span>
}
timespec_t;
在原代码16?br />timespec_t spec_t; 构造了一?timespec_t 临时对象spec_t?debug版把它各字段初始化ؓ 0xcccccccc,q得问题一下子得于曝光.而Release版本, spec_t Z个随机? 本例E中,不允?spec_t的tv_nsec为非0的Q何数,为正常尽看上去没有问题,但是q个对应的ACE_Time_Value的g不可?在特定情况下可能产生重大事故.
C++~码规范Q?br />初始化对象时要完全?/p>
声明一个结构体后,如果要对其初始化Q徏议先把它设ؓ0之后再作后箋操作Q养成这样一个习惯,׃会出现这样郁L事了?br /> 原脓出处:http://www.huihoo.com/forum/viewthread.php?tid=11016 mooyee
]]>
ŷ糱þþXXXXx |
þþwww˳ɾƷ |
ɫþþ99Ʒ91 |
ձþþþþĻ |
þþþþùaѹۿɫƬ |
99þùں;Ʒ1ӳ |
þ99Ʒһ |
þþƷɫ鶹 |
ľþþƷww16
|
þþƷˮavۺ
|
ھƷþþþӰԺձ
|
Ʒþþþ |
ŷþþþƷ |
ۺϾþøϾþúݺݺ97ɫ |
ݺɫþۺ |
ȾþӾþþƷ18 |
ƷŷƬþùŷ
|
Ʒþþþþ |
þþƷа |
þƵ |
99þþƷѿ |
þþþ뾫Ʒ |
ۺϾþþƷɫ |
AŮAVۺϾþþ |
99þۺϺݺۺϾþ |
ݺɫþþһ |
99þþƷѿһ |
ũ帾ŮëƬƷþ |
þseƷһƷ |
þþƷAV͵ |
þþþþþòҰ¸߳ |
þþþþѹۿ |
þù˾Ʒ |
þ91Ʒ91þ鶹 |
ƷþþĻ |
þþþAVۺϲҰ |
Ʒŷһþþ |
þŮվ |
2021˾Ʒþ |
һۺϾþ |
þþƷһ |