??xml version="1.0" encoding="utf-8" standalone="yes"?> 大部分h都听说过auto_ptr指针Q但是ƈ非所有h都每天用它。不使用它是不明智的Q可ȝQ,因ؓauto_ptr的设计初hZ解决C++设计和编码的普遍问题Q将它用好可以写出更健壮的代码。本文指出如何正用auto_ptr以ɽE序变得安全Q以及如何避开危险Q而不是一般用auto_ptr的恶习所致的创徏间歇性和难以诊断的问题? auto_ptr只是许许多多指针中的一U。许多商业库提供许多更强大的指针Q可以完成更多的事情。从可以理引用计数到提供更先进的代理服务等。应该把auto_ptr认ؓ是智能指针中的福特Escort[注释]Q一个基于简单且通用目的的智能指针,既没有小发明也没有丰富的Ҏ目的更不需要高性能Q但是能许多普通的事情做好Qƈ且能够适合日常使用的智能指针? auto_ptr做这样一件事Q拥有一个动态分配内存对象,q且在它不再需要的时候行自动清理的职责。这里有个没有用auto_ptr指针的不安全的例子: 我们每天都像q样写代码,如果f()只是一个三行程序,也没做什么多余的事情Q这样做当然可以很好工作。但是如果f()没有执行delete语句Q比如程序提前返回(returnQ了Q或者在执行的时候抛出异怺Q然后就D已经分配的对象没有被删除Q因此我们就有了一个经典的内存泄漏? 一个ExampleQ?Q安全的办法是用一个“智能”的指针拥有q个指针Q当销毁的时候,删除那个被指的自动分配的对象。因个智能指针被单地用ؓ自动对象Q这是Q当它离开它的作用域的时候自动销毁对象)Q所以它被称作“自动”指针? 现在q段代码不会再T对象上发生泄漏了Q不必在意这个方法是正常退是异帔R出,因ؓpt的析构函数将L在堆栈弹出的时候被调用。清理工作将自动q行?/p>
最后,使用auto_ptr和用内建指针一样地ҎQ如果要“收回”资源ƈ且再ơ手动管理的话,我们可以调用release()Q?/p> 最后,我们可以使用auto_ptr的reset()Ҏauto_ptr重置向另一个对象。如果auto_ptr已经获得一个对象,q个q程像是它先删除已l拥有的对象Q因此调用reset()Q就像是先销毁了auto_ptrQ然后重Z一个新的ƈ拥有该新对象Q? 同样Qauto_ptr也可以被用于安全地包装指针数据成员。考虑下面使用Pimpl idiomQ或者,~译器防火墙Q的例子Q?sup>[1] 单地_是C的私有细节被实现Z个单独的对象Q藏匿于一个指针之中。该思\要求C的构造函数负责ؓ隐藏在类内部的辅助“Pimpl”对象分配内存,q且C的析构函数负责销毁它。用auto_ptrQ我们会发现q非常容易: 现在Q析构函C需要担心删除pimpl_指针了,因ؓauto_ptr自动处理它。事实上Q如果没有其它需要显式写析构函数的原因,我们完全不需要自定义析构函数。显Ӟq比手动理指针要容易得多,q且对象所有权包含q对象是一个不错的习惯Q这正是auto_ptr所擅长的。我们将在最后再ơ回这个例子? 它本w很漂亮Qƈ且做得非常好Q从函数传入或传?span style="font-family: 'Courier New'" class="Code">auto_ptrsQ是非常有用的,比如函数的参数或者返回倹{?/p>
让我们看看ؓ什么,首先我们考虑当拷贝auto_ptr的时候会发生什么:一个auto_ptr获得一个拥有指针的对象Qƈ且在同一旉只允许有一个auto_ptr可以拥有q个对象。当你拷贝一个auto_ptr的时候,你自动将源auto_ptr的所有权Q传递给目标auto_ptrQ如果目标auto_ptr已经拥有了一个对象,q个对象先被释放。在拯完之后,只有目标auto_ptr拥有指针Qƈ且负责在合适的旉销毁它Q而源被讄为空QnullQ,q且不能再被当作原有指针的代表来使用? 例如Q?/p>
但是要避免陷阱再ơ用已l失L有权的auto_ptrQ? 谨记于心Q我们现在看看auto_ptr如何在源和调用者之间工作。“源”这里是指一个函敎ͼ或者其它创Z个新资源的操作,q且通常移交出资源的所有权。一个“调用者”函数反转这个关p,也就是获得已l存在对象的所有权Qƈ且通常q负责释攑֮Q。而不是有一个源和调用者,q回q且利用一个秃头指针(译者注Q而不是用一个局部变量来传递这个指针)Q虽Ӟ通过一个秃头指针来获得一个资源通常很好Q? 注意下面的微妙的变化Q?
Source()分配了一个新对象q且以一个完整安全的方式它q回l调用者,q让调用者成为指针的拥有着。即使调用者忽略了q回|昄Q如果调用者忽略了q回|你应该从来没有写q代码来删除q个对象Q对吧?Q,分配的对象也被自动安全地删除?/p>
在本文的最后,我将演示q回一个auto_ptr是一个好习惯。让q回值包裹进一些东西比如auto_ptr通常是得函数变得强健的有效方式? Sink()通过传值的方式获得对象所有权。当执行完Sink()的时候,当离开作用域的时候,删除操作被执行Q只要Sink()没有所有权转移Q。上面所写的Sink()函数实际上ƈ没有对参数做M事情Q因此调用“Sink(pt);”就{于写了“pt.reset(0);”,但是大部分的Sink函数都将在释攑֮之前做一些工作? 谨记Q千万不要以我之前没有提到的方式使用auto_ptrs。我已经看见q很多程序员试着用其他方式写auto_ptrs像他们在用其它对象一栗但问题是auto_ptrq不像其他对象。这里有些基本原则,我将把它们提出来以引起你的注意: For auto_ptr, copies are NOT equivalent. 当你试着在一般的代码中?span style="font-family: 'Courier New'" class="Code">auto_ptrs的时候,它将执行拯Qƈ且没有Q何提C,拯是不相等的(l果Q它实是拯Q。看下面q段代码Q这是我在C++新闻l经常看见的Q? 在标准容器中使用auto_ptrsL不安全的。一些h可能要告诉你Q他们的~译器或者类库能够很好地~译它们Q而另一些h则告诉你在某一个流行的~译器的文档中看到这个例子,不要听他们的? 问题?span style="font-family: 'Courier New'" class="Code">auto_ptrq不完全W合一个可以放q容器类型的前提Q因为拷?span style="font-family: 'Courier New'" class="Code">auto_ptrs是不{h的。首先,没有M东西说明Qvector不能军_增加q制造出“扩展”的内部拯。再ơ,当你调用一个一般函数的时候,它可能会拯元素Q就像sort()那样Q函数必L能力假设拯是等L。至一个流行的排序拯“核心”的元素Q如果你试着让它?span style="font-family: 'Courier New'" class="Code">auto_ptrs一起工作的话,它将拯一份“核心”的auto_ptr对象Q因此{UL有权q且所有权转移l一个时对象)Q然后对其余的元素也采取相同的方式(从现有成员创建更多的拥有所有权的auto_ptrQ,当排序完成后Q核心元素将被销毁,q且你将遇到一个问题:q组序列里至一个auto_ptrQ也是刚才被掉包的那个核心元素Q不再拥有对象所有权Q而那个真实的指针已经随着临时对象的销毁而被删除了! 于是标准委员会回退q希望做一些能够帮助你避免q些行ؓ的事情:标准的auto_ptr被故意设计成当你希望在用标准容器的时候用它时打断你Q或者,臛_Q在大部分的标准库实C打断你)。ؓ了达到这个目的,标准委员会利用这样一个技巧:?span style="font-family: 'Courier New'" class="Code">auto_ptr's的拷贝构造函数和赋值操作符的右|rhsQ指向非帔R。因为标准容器的单元素insert()函数Q需要一个常量作为参敎ͼ因此auto_ptrs在这里就不工作了。(译者注Q右g能赋值给非常量) 一个auto_ptr设计?span style="font-family: 'Courier New'" class="Code">const auto_ptrs不再丢失所有权Q拷贝一个const auto_ptr是违法的Q译者注Q没有这L构造函敎ͼQ实际上你可以针对它做的唯一事情是通过operator*()或者operator->()解引用它或者调用get()来获得所包含的指针的倹{这意味着我们有一个简单明了的风格来表达一个绝不丢失所有权的auto_ptrQ? q就是我要说的cosntQ因此如果现在你要向世界证明你的auto_ptr是不会被改变q且L删除其所有权Q加上const是你要做的。const auto_ptr风格是有用的Q你必须它谨记于心? 最后,auto_ptr对写出异常安全的代码有时候非常必要,思考下面的代码Q?/p>
该函数有两个可见的作用:它输Z些内容,q且q回一个String。关于异常安全的详细说明出了本文的范围[2]Q但是我们想要取得的目标是强异常安全的保障Q归lؓ保函数的原子性——如果有异常Q所有的作用一起发生或者都不发生? 虽然在例10(a)中的代码非常_yQ看h相当接近于异常安全的代码Q但仍然有一些小的瑕疵,像下面的客户代码所C: 因ؓl果通过D回,因此String的拷贝构造函数将被调用,而拷贝赋值操作符被调用来结果拷贝到theName中。如果Q何一个拷贝失败了Qf()完成了所有它的工作以及所有它的Q务(q很好)Q但是结果是无法挽回的(哎哟我的妈呀Q? 我们可以做的更好吗,是否可以通过避免拯来避免这个问题?例如Q我们可?让函数有一个非帔R引用参数q向下面q样q回| q看h很棒Q但实际不是q样的,q回result的赋值的函数只完成了一个功能,而将其它事情留给了我们。它仍然会出错。因此这个做法不可取? 解决q个问题的一个方法是q回一个指向动态分配指针的String对象Q但是最好的解决Ҏ是让我们做的更多Q返回一个指针包含在auto_ptrQ? q里是一个技巧,当我们有效隐藏所有的工作来构造第二个功能Q返回|当确保它可以被安全返回给调用者ƈ且在W一个功能(打印消息Q完成的时候没有抛出操作。我们知道一旦cout完成Q返回值将成功交到调用者手中,q且无论如何都会正确清理Q如果调用者接受返回|调用者将得到q个拯的auto_ptr临时对象的所有权Q如果调用者没有接受返回|也就是忽略返回|分配的String在临时auto_ptr被销毁的时候自动清理。这U安全扩展的代h呢?像我们l常实现的强异常安全一P强安全通常消耗一些效率(通常比较)——这里指额外的动态内存分配。但是当我们在效率和正确性之间做出选择的话Q我们通常会选择后者! 让我们养成在日常工作中用auto_ptr的习惯。auto_ptr解决了常见的问题Qƈ且能够你的代码变得更安全和健壮Q特别是它可以防止内存泄漏以及确保强安全。因为它是标准的Q因此它在不同类库和q_之间是可UL的,因此无论你在哪里使用它,它都是对的? This article is drawn from material in the new book Exceptional C++: 47 engineering puzzles, programming problems, and exception-safety solutions by Herb Sutter, © 2000 Addison Wesley Longman Inc., which contains further detailed treatments of points touched on briefly in this article, including exception safety, the Pimpl (compiler-firewall) Idiom, optimization, const-correctness, namespaces, and other C++ design and programming topics. Pimpl风格可以有效减少目构徏旉Q因为它在CU有部分改变的时候,L客户代码引vq泛的重新编译。更多关于Pimpl风格以及如何部v~译器墙Q参考这?a href="xc++.htm">Exceptional C++的条?6?0。(Addison-Wesley, 2000Q? See the article originally published in C++ Report and available on the Effective C++ CD (Scott Meyers, Addison-Wesley, 1999) and Items 8 to 19 in Exceptional C++ (Herb Sutter, Addison-Wesley, 2000). q里Q?我们从C++的基本语义看上去Q?应该是Type(i) 调用一ơ拷贝构造函敎ͼ 在堆栈中生成一个时对象;然后Q用该对象构造返回对象;然后对这个时对象调用析构函敎ͼ在调用者方Q?用返回的临时对象调用拯构造函C初始化对象t, q回对象的析构函数在q之后, 函数q回之前调用?
所以, Type t = get(i); 应该有三个拷贝构造函数和两个析构函数的调?
可是Q?q有一U说法是Q?~译器可能会对这两个临时对象q行优化Q最l的优化l果会是只有一ơ的构造函数。因为很明显地可以看刎ͼ q里我们其实只是要用一个整数构造一个Type对象?
? g很有道理Q?
那么Q?哪一U说法对呢? 没有调查没有发a权,于是本h用VC++6.0做了实验?放了些cout<<?.在拷贝构造函数里Q观察打印的l果Q?l果却是跟我的simple, naïve的预一致。三个拷贝构造函敎ͼ 两个析构函数?
“你个弱智编译器Q脑袋进水了吧??忘了~译器没脑袋?“很明显在这个例子里我的两个临时对象都没有用的啊Q?
于是Q上|, 查资料, google一下吧Q?
下面是我查到的一些结果:
其实Q?q种对g递的优化的研IӞ q不只局限于q回倹{对下面q个例子Q? 也有q种考虑?
f(T)是按g递的。语义上应该做一个复Ӟ 使得函数内部对T的改变不会媄响到原来的t1.
但是Q因为在调用f(t1)之后Q?我们没有再用t1(除了一个隐含的destructor调用)Q是否可能把复制优化掉, 直接使用t1呢?q样可以节省掉一个拷贝构造函数和一个析构函数?
可是Q?不论是对q回值的优化Q?q是对上面这U局部对象的优化Q在1995q的C++新标准草案出台前都是为标准所严格限制?(虽然有些~译器ƈ没有遵行q个标准Q?q是支持了这U“优化?
那么Q?q又是ؓ什么呢Q?
q里面涉及到一个普遍的对side-effect的担忧?
什么又是side-effect呢?
所谓side-effect是一个函数的调用与否能够对系l的状态造成区别?
int add(int i, int j){ return i+j; }是没有side-effect的,?
void set(int* p, int I, int v){ p[I]=v; }是有side-effect的。因为它改变了一个数l元素的| 而这个数l元素在函数外是可见的?
通常意义上来_ 所有的优化应该在不影响E序的可观察行ؓ的基上进行的。否则,快则快了Q?l果却和所惌的完全不同!
而C++的拷贝构造函数和析构函数又很多都是有side-effect的。如果我们的“优化”去掉了一个有side-effect的拷贝构造函数和一个析构函敎ͼ q个“优化”就有可能改变程序的可观察行为。(注意Q?我这里说的是“可能”,因ؓ“负负得正”, 两个有side-effect的函数的调用Q?在不考虑q行q行的情况下Q?也许反而不会媄响程序的可观察行为。不q, q种塞翁失马的事儿, ~译器就很难判断了)
Zq种忧虑, 1995q以前的标准Q?明确止对含有side-effect的拷贝构造函数和析构函数的优化。同Ӟ q有一些对C++扩充的提议, 考虑让程序员自己对类q行允许优化的声明?E序员可以明地告诉~译器:不错Q?我这个拷贝构造函敎ͼ 析构函数是有side-effect, 但你别管Q?管优化Q?Z事有我呢Q?
哎, side-effect真是一个让人又恨又q东西Q它使编译器的优化变得困难;加大了程序维护和调试的难度。因?functional language 把side-effect当作z水猛兽一Pq脆止。但同时Q我们又很难dside-effect. 不说E序员们更习惯于imperative 的编E方? 象数据库操作QIO操作都天然就是side-effect.
不过Q个是认为C++标准对“优化”的保守态度是有道理的。无论如何,让“优化”可以潜在地偷偷地改变程序的行ؓL让h惌v来就不舒服的?
但是Q?矛盾是对立统一的。(惛_q俺马列可得了八十多分呢Q?对这Uaggressive的“优化”的呼声是一高q一?以Stan Lippeman为首的一撮固分子Ҏ准的颠覆和和qx变的阴谋从来没有停止过?q不Q在1996q的一个风雨交加的夜晚Q?一个阴险的C++新标准草案出炉了。在q个草案里, 加入了一个名为RVO (Return Value Optimization) 的放宽对优化的限Ӟ 妄图走资本主义道路, l资本家张目的提案。其具体内容是_允许~译器对命名q的局部对象的q回q行优化Q?即拯构造函?析构函数有side-effect也在所不惜。这个提议背后所隐藏的思想是Qؓ了提高效率, 宁可冒改变程序行为的风险。宁要资本主义的苗, 不要C会M的草了!
我想Q?q样的一个罪大恶极的提案竟会被提交,应该是因为C++的值拷贝的语义的效率实在太“妈妈的”了?当你写一?Complex operator+(const Complex& c1, const Complex& c2);的时候, 竟需要调用好几次拯构造函数和析构函数Q同志们Q(沉痛圎ͼ 语重心长圎ͼC会M的生产关pȝ优越性怎么体现啊?
接下来, 当我想Google C++最新的标准Q?看RVO是否被最l采UxQ?却什么也找不C?到ANSI的网站上去, 居然要付钱才能DOWNLOAD文?“老子在城里下馆子都不付钱Q?down你几个烂文q要l钱Q!?
故事没有l局Q?实在是不爽?也不知是不是因ؓ标准q没有敲定, 所以VC++6 没有优化, q是VCҎ没完全遵守标准?
不过Q有一Ҏ肯定的?当写E序的时候, 最好不要依赖于RVO (有hQ?象Stan Lippeman, 又叫它NRV优化)?因ؓQ?不论Ҏ准的争论是否已经有了l果Q?实际上各个编译器的实Cq是各自为政Q?没有l一?一个叫SCOtt Meyers的家?忘了是卖什么的?pQ?如果你的E序依赖于RVO, 最好去掉这U依赖。也是_ 不管RVO到底标准不标准, 你还是不能用?不仅不能用, q得时刻警惕着RVO可能带来的程序行Z的变化?Q也不知q帮家伙瞎忙了半天到底ؓ啥!Q?
说到q里Q?倒想起了C#里一个困惑了我很久的问题。记得读C#的specification的时候, 非常不解Z么C#不允许给value type 定义析构函数?
q里Q?先简略介l一下C#里的value type (原始数据cdQ?struct cd)?
在C#里的value_typep是| 永远只能copy, 取倹{因此, 它永q是in-place的。如果你把一个value type的数据放在一个对象里Q它的生命期和那个对象相同Q如果你声明一个value type 的变量在函数中, 它的生命期就在lexical scope里?
{
The_ValueType value;
}//value 到这里就死菜?
啊呀呀Q?q不正是我们怀늚C++的stack object吗?
在C++里,Auto_ptr, shared_ptr, 容器们, 不都是利用析构函数来理资源的吗Q?
C#QJava 虽然利用garbage collection技术来攉无用对象Q?使我们不用再担心内存的回收?但garbage collectionq不保证无用对象一定被攉Q?q不保证Dispose()函数一定被调用Q?更不保证一个对象什么时候被回收?所以对一些非内存的资源, 象数据库q接Q?|络q接Q?我们q是希望能有一个类gsmart pointer的东西来帮我们管理啊。(try-finally 虽然可以用, 但因为它影响到lexical scope, 有时用v来不那么方便Q?
于是Q?我对C#的取消value type的析构函数充满了深厚的阶U仇恨?
不过Q?现在xQ?C#的这U设计一定是惩于C++p|的教训:
1. value type 没有拯构造函数。C#只做~省copy, 没有side-effect 对以下程序:
The_Valuetype get(int I){return The_Valuetype(i);}
The_Valuetype t = get(1);
在C#里我们可以快乐地_只调用了一ơ构造函数?再没有side-effect的沙漠, 再没有难以优化的荒原Q?smart pointer望而却步, 效率之花处处开遍?I have a dream, …?/p>
转蝲自:http://gugu99.itpub.net/post/34143/466008Z么它是一个“自动”指?
// Example 1(a): Original code
//
void f()
{
T* pt( new T );
/*...more code...*/
delete pt;
}
// Example 1(b): Safe code, with auto_ptr
//
void f()
{
auto_ptr<T> pt( new T );
/*...more code...*/
} // cool: pt's destructor is called as it goes out
// of scope, and the object is deleted automatically
// Example 2: Using an auto_ptr
//
void g()
{
T* pt1 = new T;
// right now, we own the allocated object
// pass ownership to an auto_ptr
auto_ptr<T> pt2( pt1 );
// use the auto_ptr the same way
// we'd use a simple pointer
*pt2 = 12; // same as "*pt1 = 12;"
pt2->SomeFunc(); // same as "pt1->SomeFunc();"
// use get() to see the pointer value
assert( pt1 == pt2.get() );
// use release() to take back ownership
T* pt3 = pt2.release();
// delete the object ourselves, since now
// no auto_ptr owns it any more
delete pt3;
} // pt2 doesn't own any pointer, and so won't
// try to delete it... OK, no double delete
// Example 3: Using reset()
//
void h()
{
auto_ptr<T> pt( new T(1) );
pt.reset( new T(2) );
// deletes the first T that was
// allocated with "new T(1)"
} // finally, pt goes out of scope and
// the second T is also deleted
包装指针数据成员
// Example 4(a): A typical Pimpl
//
// file c.h
//
class C
{
public:
C();
~C();
/*...*/
private:
class CImpl; // forward declaration
CImpl* pimpl_;
};
// file c.cpp
//
class C::CImpl { /*...*/ };
C::C() : pimpl_( new CImpl ) { }
C::~C() { delete pimpl_; }
// Example 4(b): A safer Pimpl, using auto_ptr
//
// file c.h
//
class C
{
public:
C();
/*...*/
private:
class CImpl; // forward declaration
auto_ptr<CImpl> pimpl_;
};
// file c.cpp
//
class C::CImpl { /*...*/ };
C::C() : pimpl_( new CImpl ) { }
所有权Q源Q以及调用?Sinks)
// Example 5: Transferring ownership from
// one auto_ptr to another
//
void f()
{
auto_ptr<T> pt1( new T );
auto_ptr<T> pt2;
pt1->DoSomething(); // OK
pt2 = pt1; // now pt2 owns the pointer,
// and pt1 does not
pt2->DoSomething(); // OK
} // as we go out of scope, pt2's destructor
// deletes the pointer, but pt1's does nothing
// Example 6: Never try to do work through
// a non-owning auto_ptr
//
void f()
{
auto_ptr<T> pt1( new T );
auto_ptr<T> pt2;
pt2 = pt1; // now pt2 owns the pointer, and
// pt1 does not
pt1->DoSomething();
// error! following a null pointer
}
// Example 7: Sources and sinks
//
// A creator function that builds a new
// resource and then hands off ownership.
//
auto_ptr<T> Source()
{
return auto_ptr<T>( new T );
}
// A disposal function that takes ownership
// of an existing resource and frees it.
//
void Sink( auto_ptr<T> pt )
{
}
// Sample code to exercise the above:
auto_ptr<T> pt( Source() ); // takes ownership
不可以做的事情,以及Z么不能做
// Example 8: Danger, Will Robinson!
//
vector< auto_ptr<T> > v;
/* ... */
sort( v.begin(), v.end() );
使用const auto_ptr是一个好习惯
// Example 9: The const auto_ptr idiom
//
const auto_ptr<T> pt1( new T );
// making pt1 const guarantees that pt1 can
// never be copied to another auto_ptr, and
// so is guaranteed to never lose ownership
auto_ptr<T> pt2( pt1 ); // illegal
auto_ptr<T> pt3;
pt3 = pt1; // illegal
pt1.release(); // illegal
pt1.reset( new T ); // illegal
auto_ptr以及异常安全
// Example 10(a): Exception-safe?
//
String f()
{
String result;
result = "some value";
cout << "some output";
return result;
}
String theName;
theName = f();
// Example 10(b): Better?
//
void f( String& result )
{
cout << "some output";
result = "some value";
}
// Example 10(c): Correct (finally!)
//
auto_ptr<String> f()
{
auto_ptr<String> result = new String;
*result = "some value";
cout << "some output";
return result; // rely on transfer of ownership;
// this can't throw
}
致谢
注释
]]>Type get(int I){
return Type(i);
}
Type t = get(1);
void f(T t) { }
void main(void){
T t1;
f(t1);
}
2. value type 不准有析构函数。C#有garbage collection, 析构函数的唯一用途只会是做一些side-effect象关闭数据库q接?所以取消了析构函数Q?取消了value type的side-effect.
3. 没有了side-effect, pȝ可以L地做优化?
]]>自旋锁同?/h3>
以上内容摘自《编E之》P150-154?/p>
Z方便使用Q下面是可拷贝的代码Q?/p>
Math.h
#pragma once class Math { public: Math(void); ~Math(void); public : //~程之美P150-154 //求最大公U数Q欧几里德——辗转相除法 static int Gcd1(int x, int y); //求最大公U数Q欧几里德——辗转相除法Q变相将除法变成了减法) static int Gcd2(int x, int y); static int Gcd3(int x, int y); inline static bool IsEven(int x); inline static int Absolute(int x); };
Math.cpp
#include "Math.h" Math::Math(void) { } Math::~Math(void) { } int Math::Gcd1(int x, int y) { //y, x%y序不能错; return y ? Gcd1(y, x % y) : x; } int Math::Gcd2(int x, int y) { //与Gcd1相同的方式,但由于x%y计算速度较x-y要慢Q但效果相同Q所以换用x - y // 但用减法和除法不同的是,比如和,%20=10Q?20=70Q也是-4×=10 // 也就是说q代ơ数较Gcd1而言通常是增加了? return y ? Gcd1(y, x - y) : x; } int Math::Gcd3(int x, int y) { if(x < y) return Gcd3(y, x); if(y == 0) return x; else { if(IsEven(x)) { if(IsEven(y)) return (Gcd3(x >> 1, y >> 1) << 1); else return Gcd3(x >> 1, y); } else { if(IsEven(y)) return Gcd3(x, y >> 1); else return Gcd3(y, x - y); } } } bool Math::IsEven(int x) { return !(bool)x & 0x0001; } int Math::Absolute(int x) { return x < 0 ? -x : x; }
Main.cpp
#include <stdafx.h> #include <iostream> #include "Math.h" using namespace std; int _tmain(const int & arg) { cout<<"Math::Gcd1(42,30) = "<<Math::Gcd1(42,30)<<endl; cout<<"Math::Gcd1(30,42) = "<<Math::Gcd1(30,42)<<endl; cout<<"Math::Gcd1(50,50) = "<<Math::Gcd1(50,50)<<endl; cout<<"Math::Gcd1(0,0) = "<<Math::Gcd1(0,0)<<endl; cout<<"Math::Gcd1(-42,-30) = "<<Math::Gcd1(-42,-30)<<endl; cout<<"Math::Gcd1(-42,30) = "<<Math::Gcd1(-42,30)<<endl; cout<<"------------------------------"<<endl; cout<<"Math::Gcd2(42,30) = "<<Math::Gcd2(42,30)<<endl; cout<<"Math::Gcd2(30,42) = "<<Math::Gcd2(30,42)<<endl; cout<<"Math::Gcd2(50,50) = "<<Math::Gcd2(50,50)<<endl; cout<<"Math::Gcd2(0,0) = "<<Math::Gcd2(0,0)<<endl; cout<<"Math::Gcd2(-42,-30) = "<<Math::Gcd2(-42,-30)<<endl; cout<<"Math::Gcd2(-42,30) = "<<Math::Gcd2(-42,30)<<endl; cout<<"------------------------------"<<endl; cout<<"Math::Gcd3(42,30) = "<<Math::Gcd3(42,30)<<endl; cout<<"Math::Gcd3(30,42) = "<<Math::Gcd3(30,42)<<endl; cout<<"Math::Gcd3(50,50) = "<<Math::Gcd3(50,50)<<endl; cout<<"Math::Gcd3(0,0) = "<<Math::Gcd3(0,0)<<endl; cout<<"Math::Gcd3(-42,-30) = "<<Math::Gcd3(-42,-30)<<endl; cout<<"Math::Gcd3(-42,30) = "<<Math::Gcd3(-42,30)<<endl; return 0; }
不过有一点值得一提,是所谓性能最好效率最高的Gcd3不支持负敎ͼ也就是最后两行测试代码无法通过。但是限于对负数的最大公U数q没有定义,也就是说即便上面的Gcd1和Gcd2好像出了负敎ͼ但它们的l果没有意义?/p>
固定链接Q?a href="/mymsdn/category/3173.html">http://www.shnenglu.com/mymsdn/category/3173.html
文章标题Q十qMFCl历认识的Microsoft技?ZT)
关键?/strong>QMFC、Microsoft、技术对比、技术发?br />转蝲?/strong>Q?a >http://blog.vckbase.com/hangwire/archive/2005/05/26/5806.html
作?/strong>Qhangwire
发表旉Q?005-05-26 09:13
我最初知道MFC大概是在1993q_那个时候Visual C++q没面世Q当时Microsoft的C++~译器还很弱Q官方的名字是Microsoft C/C++ 7.0QMFC的版本是1.0Q几乎没有引起什么反响,那个时期最好的C++开发环境是Borland C++ 3.1Q其实,大概?992q?1月䆾Q一个偶然的ZQ我领略到Borland公司的厉宻IC得在什么地方,我看C个绝妙的集成开发环境,即Turbo C++ 3.0 for WindowsQ这是我记忆中第一个真正的Windows环境下的C++集成开发环境,那种Ȁ动的感觉至今仍记忆犹斎ͼ不客气的_当时臛_在C++斚wQMicrosoft与Borland不是一个水q的QBorland明显的要高于Microsoft QBorland的品在技术上l我留下深刻的印象。那个时候Microsoft最好的开发^台是Visual Basic 3.0Q而Borland的Delphi正处于开发阶D(Delphi 的代码名U是Q?VB Killer"Q……,惌vq些十几q前的往事,我不感慨万千?/p>
十几q来Q我用过许多开发环境,关于Visual BasicQ我用过最早的DOS版本QWindows版的Visual Basic我基本上全都用过Q至今我q记得每个版本的VB安装盘磁盘的盘数。同P我用q各个版本的DelphiQ特别是Delphi 2.0Q给我留下极好的印象。Delphi提供真正~译的可视化开发环境,那个时候(1994q左叻IQDelphi可以开发带有GUI的动态链接库Q你可以惌Q在Microsoft Access 2.0的应用程序中可以加蝲一个Delphi Formq进行程序交互,那种感觉真是极了?/p>
Borland C++是我心中无法Ҏ的遗憾,从Turbo C到C++ BuilderQ我深刻的体验到Borland的辉煌和无奈QDelphi从VB Killer走到为VB护航Q你可以惌Delphi一步到位的ActiveX 控g开发技术有多牛Q早期的VB有多土,早期的VB不能开发动态链接库Q因此无法开发ActiveX 控gQ想h真o人嘘唏不ԌQBorland C++的命q也是不。Borland C++ 3.1的辉煌永q不再了Q十几年的开发工作中Q我在C++上投入了大量的精力,Borland C++曄l我带来无数的激动,然而这个经典的名字却在与Microsoft的竞争中渐渐的流逝了……?/p>
MFC4.0的出玎ͼ使得Z感觉Microsoft在C++斚w赶上来了Q这一版的MFC是Win95推出后出现在Visual C++ 4中(Microsoft没有VC 3QVC4以前的版本是2.2?.1?.0?.51?.5?.0Q。也许是对Borland C++的潜意识的失望,我不知不觉的接受了MFCQVC 4.2推出Ӟ我通过正常渠道购买了这个编译器的企业版?/p>
二、关于Microsoft
关于MicrosoftQ有无数的h要对q个名字叙说感觉Q这个o厌的名字Q不知道是喜Ƣ还是憎Ӟ你是E序员,你的心思可能就要因Microsoft的存在而动Q即使你用LinuxQ你可能也是因ؓMicrosoft技术因素。多年来,q个名字每天都出现在你、我、他的面前,因ؓ你不得不面对Windows的存在,可是你憎恨这个名字吗Q你讨厌q个名字吗?我不知道是否已经对这个名字麻木了?/p>
1998q我个h订了Microsoft MSDN Universal 版,我开始比较全面接触这个公司的开发技术,你可以想象,1998q当你面对上癑ּ技术光盘的时候,你就知道什么叫?厚度"Q当我们有时说出"赶上"?"辑ֈ"Microsoft某些产品的水q的时候,可能我们~Z对这个公?厚度"的真实了解。进入MSDNQ我感觉Microsoft直不是一?公司"Q而是Q或者正在Ş成)一?C会"?/p>
当时著名的技术网?a >http://www.codeguru.com全部的技术资料是可下载的Q那个时?a >http://www.codeguru.com提供整个|站内容下蝲服务Q大U?M左右Q,大名鼎鼎?a 的景象?可能很多人想q,如果Borland不存在,对Microsoft不是更有力吗Q其实Microsoft可能_N中国历Ԍ读过《三国》、十分了解战国时期的中国Q其实Borland形式上的存在Q对Microsoft是十分有利的Q至Ş式上q有竞争ҎQ而事实上Borland已经受控于MicrosoftQMicrosoft是Borland的大股东Q。你可以看到一些微妙的现象QBorland为Microsoft提供了大量的人才Q其中包括Delphi总设计师以及Borland C++~译器的核心成员Q同时也为Microsoft .NET提供强有力的护航服务Q看看C# Builder、Delphi .NETQ?998qMicrosoft 的COM技术基本已l成熟,q个技术人感到震|当时Microsoft的对手们提出"OpenDoc"用于Ҏ"COM"Q你看看"OpenDoc"阵营的几个成员:IBM、Apple、Borland、NovellQ你会感到这个阵营十分豪华、强大。但l果却差Zh意,"OpenDoc"无疾而终Q?COM"依然生机勃勃?/p>
有h?COM"没落了,那么太不了解Microsoft了。在?OpenDoc"的竞争中Q?COM"是个d的胜利者,在与"Java"的竞争中Q?COM"成功的进化了Q在q个q程中Microsoft体现了强大的吸收能力、以及无法想象的韧劲?NET只不q是COM?别名"而已。对于一个经验丰富的C++E序员而言Q?NET是COM的进化,而Microsoft内部.NET是"COM 3.0"QOLE2是COM 2.0Q,?CLR"是一个不择不扣的COM对象。曾l有人问我,既然牛顿时代奠定了基础Q想惌名的牛顿-莱布D公式Q,几百q后的今天,数学q研I?微积?吗?回答当然是依然在研究Q?微积?早期是针对函数的Q现?微积?是针?ŞQManifoldQ、纤l丛QFiber BundleQ?的,概念深奥了,可是基本思想不变Q只?微积?的思想得到合理的g拓与q化Q你了解Microsoft吗?Microsoft Research有一批超一的数学家在为Microsoft工作Q其中一些是斐尔兹奖的得主,Microsoft正在实现如同"微积?q化?微分Ş"一样将"COM"q化?.NET"。从U学概念角度上分析COM与JavaQ可能COM更全面、精,从实现的成熟度上Java可能更成熟,可是你看刎ͼMicrosoft正在不紧不慢的追赶。Microsoft令h联想h国时期的强秦?/p>
战国时期的秦国,采取"q交q攻""抚弱掠强"{措施傲视六国,今天的Microsoft也是q样QVB1.0ӞMicrosoft推出"VBX"控g技术,众多的小公司得以生存QMicrosoft自己不开?VBX"lgQ同?VBX"q化?OCX"ӞMicrosoftq不十分强大Q可是这U试探得C多小公司的响应?997qMicrosoft Office 97?998qMicrosoft推出Visual Studio 6.0Q给众多中、小公司提供了生存、发展的ZQ例如Microsoft Office 97中集成了Visual Basic for Application 5.0Q这Ҏ术得几癑֮软g开发商与Microsoft{v了VBA技术许可协议,即AutoDeskq样的公叔R与Microsoft{v了这个协议,q个协议使得每个集成VBA的品的l个用户许可为Microsoft?0$的许可费Q如果你了解VSIPQVisual Studio Integration ProtocolQ协议,以及有多公司签订了VSIP协议Q你q正感觉到Microsoft的可怕;Microsoft Office 97、Visual Studio 6.0的用L面十分漂亮,Z么Microsoft自己的开发工具不提供cM的Y件组Ӟ你看C多第三方的Microsoft盟友UL推出自己的界面库以模仿MicrosoftQ他们不会反对MicrosoftQ因Z们已lŞ成了使得Microsoft以及q些公司得以生存的生态圈?/p>
Microsoft的技术储备有多少QMicrosoft之外的h很难说清楚,Microsoft中国公司也未必了解多,1999qWTLcd刚刚出现的时候,Z希望WTL能得到官方的支持Q或授权l一个Microsoft之外的一个公司(你能惌出Borland C++ 5.0内置的ActiveX开发机制是ZMicrosoft ATLcd吗?Q,直到今天QWTL依然如故Q我们完全相信,如果Microsoft强力推广WTLQWTL完全可以行Q可是Microsoft不缺cM的技术,cM的类库还有BCL(Base Control LibraryQ一个用于开发轻量ActiveX控g的类?QMicrosoftq有一个基于ATL的类库,q个cd用于开发ActiveX DesignerQActiveX Designer是绝大多数程序员不了解的一cd象,如果你熟悉Office开发,你知道Office VBA 中有一cd象,即Form2Q此外VB6.0 中的报表设计器(以及著名的Active ReporterQ,都属于此cd象,用这个类库,你可以ؓVB6.0以及集成VBA的系l提供定制化的可视化设计机制{等Q如今ActiveX Designer已经演化为集成于Visual Studio .NET中的设计器?/p>
三、向Microsoft学习
无论从什么角度评价MicrosoftQ我觉得Microsoft是值得我们学习的,如果说生zdq个时代有Microsoft存在是一场灾难,你就应该痛恨q个家伙Q但你首先要向这个家伙学习!我无意ؓMicrosoft歌功颂dQ我只是惌出十几年我对Microsoft技术的感受?/p>
Microsoft在研I式的开发中受益极大Q如果你有兴,你可以访?a U学无国?。技术是否有国界Q不知道是否有定论?Q想想DVD{技术专利给国内业界带来的灾难,不知道应不应该痛定思痛Q在Microsoft校园招聘现场的气氛中Q我g明白了ؓ什么国?原创技?得可怜。我读过几本Microsoft亚洲研究院的高手写的书,明显可以看出QBill gate 是他们的_领袖以及他们对Microsoft的虔诚,国内的研I机构应当研I一下Microsoft的用Z道,Microsoft好像是三国里的h物,不知是刘备还是曹操,或者二者的混合物。我l常路过西格玛大厦,W一ơ西格玛大厦q入真有"朝圣"的感觉,也与Microsoft中国的几个层ơ的人打q交道,各中滋味实在一a隑ְ?/p>
在Office大战中,国软g的确在一些方面与Microsoftq行较量Q其实给人的感觉很勉强,界面上的似是而非Q或用户习惯斚w的接qƈ不能解决Ҏ的问题,一个好的Y件开发h员必L一个Y件用的高手Q很难想象一个Y件操作水q_拙劣的开发h员能开发出高水q的软gQ我最早用的软g之一是Microsoft WordQ当时的版本?.0Q大概是1992q的事情Q给我留下深d象的是集成于Word中的Word BasicQ后来,我接触到Excel 3.0Q不出所料,Excel中集成的是Excel BasicQ后来用的Access中自然内|Access Basic 1.0Q在q些软g集成捆绑成Office之前Q我感觉这些品的构思十分了不vQ很hMicrosoft的风|因ؓ你知道,即是一个DOSQMicrosoft都要提供一个内|的QBasic或GW Basic。虽然关于Microsoft的品评论很多,作ؓ一个技术h员,我认为Microsoft的品构思绝ҎW一的Q从1994q早期的Officepd?997qŞ成的Office 4.2Q我认ؓQ技术构思上均领先于我国2002q以后的Office产品Q你听说q如下说法吗Q?Dos 作ؓ操作pȝ的时代,Windows是应用YӞWindows是操作系l时QOffice成ؓDos时代的WindowsQ那么如果按此规律,Office会不会替代Windows而成为操作系l?"Q现在在开发领域Visual Studio( .NET)正在成ؓ另一个OfficeQ你注意C吗?控制Visual Studio( .NET)集成开发环境的仍然是一个Basic语言引擎QVisual Basic .NETQ?
与许多公怸同的是,在技术体pMQMicrosoft几乎所有的产品是息息相关的QWindows、Office、Visual Studio .NET虽然各不相同Q但公共的核心即Ş成,我们已经看到Q核心组件方面,Office与Visual Studio .NET日渐于一_例如Microsoft正在Office 2003的核心组件VBA 6.X逐步用新的Visual Studio Tools for Office替代Q而我们依然在一些似是而非的现象上与Microsoft的品比较差距,国家采购或政府采购支持的公司Q不去钻研核心技术,只是急功q利的采用短期行为急于与Microsoft怺Q不知是否有蚍蜉撼树的感觉,个h的体验是Q先学习MicrosoftQ踏t实实的学,了解MicrosoftQ深入的了解Q然后再喊口受?/p>
四、ؓ什么用MFCQ?/p>
l过若干q的竞争QBorland 的OWL几乎消失了,q个OWL是个非常漂亮的C++cdQ在Borland C++ 3.1风光无限的年代,OWL真正的做C独领风骚。然而,Borland C++ 4.0错过了进?2位程序的最x机,BC 4.0推出后不久,q来了Win95QBorland仓促上阵Q以一个小?Pack"使得BC4可以~译ZWin4的程序,当时的Visual C++?.0版,支持Window16的版本ؓVisual C++1.51Q有意思的是Borland可以用同一个编译器同时支持Win16、Win32Q而Microsoft却不得不为Win16、Win32提供不同的编译器。然而,非正式版本的Visual C++ 2.1与Visual C++ 2.2却悄悄地支持了Win95的最新特征,即Win95新提供的一l公共控Ӟ在我的印象中QBorland对Win95新特征的支持不利使得MFC与OWL的距L大的~短了。稍后到来的Borland C++ 4.5没有改变q个状况Q尽Borland C++ 5.0同时支持OWL与MFCQ可是|象已l显ԌBorland C++非常遗憾的只走到?.5版。C++ Builder虽然形式上引入了Delphi的VCL库,可是许多C++E序员ƈ不买账,因ؓ许多以C++Z的h更喜Ƣ以~辑的模式进行编码。Visual C++ 4.0的出玎ͼ在C++q个战场上,Borland开始落败了?/p>
MFC发展C天,已经十多q了Q尽褒贬不一Q但可以肯定Q十几年的技术积累已l奠定了MFC的生存基Q即使Microsoft的长角发布,MFC也不能推出Windows的舞収ͼ事实上,长角QLonghornQ之后的Visual Studio .NET仍将MFC作ؓ一个重要的l成部分Q在今年的Visual Studio .NET 2005中,MFC在C++中的位置依然如故。MFC的未来,应该不必担心Q只要你深入考察.NETcdQ你会发玎ͼMFC的许多思想机制正悄然进?NETQ与此同ӞMicrosoft的第三方盟友十多q来已ؓMFC开发了大量的扩展库Q如果Microsoft是船Q第三方盟友是载舟之水。许多h认ؓMFC不发展了Q其实是一U错觉,Visual C++ 6的界面十分经典,特别是其中的Docking控制条机Ӟ其实Visual C++ 6的IDE完全是MFC写的Q可是MFCcd中控制条相关的类功能很弱Qؓ什么?你会看到许多与Microsoft友好的公司,他们很快的在MFC基础上实CVisual C++ 6 的Docking机制Q这是Microsoft的高明之处,Microsoft很会l盟友提供机会,其一贯的做法是在自q商品化品中预先提供一些有的特征Q得其他一些公司进行模仿以带动用户体。Borland不具备这L储备。MFCW三方市场的J荣Q得益于Microsoft的策略与明智。MFC可否跨^収ͼ理论上完全可以,Microsoft不做Q也是策略,但是有许多重要的产品Microsoft却默许MFCUL到其他^収ͼ事实上,Microsoft的合作伙伴之一Mainsoft公司QWindows源码是从这家公司流qQ,几年来就是负责移植MFCE序UL到UINIX、Linux、AIX{操作系l之上?/p>
新版的Visual C++中MFC已经支持.NET开发了QMFC与ATL的协作更好了。根据我的经验,MFC、ATL?NET库三者完全可以融合在一L合应用到实际的开发工作中去,如果你是MFC行家Q我希望ATL?NET库能成ؓ你的忠实的左x。那么有没有同时支持MFC、ATL?NET库的E序Q当然有QVisual Studio .NET IDE是Q而且Visual Studio .NET IDEq支持用ATL?NET库扩展的AddinQ如果你希望用MFC理ATL?NET库,Ll支持我Q?/p>
五、认识Application对象
如果你熟悉Microsoft OfficeQ你应该q一步的剖析q个大型软gQMicrosoft Office中几乎每个程序都是可二次开发的Q这一点得益于Microsoft Office内置的二ơ开发机Ӟ一个是ZCOM机制的VBA模型Q另一个是Z.NET框架的托模型:Visual Studio Tools for Office。作Z名程序员Q你应当在技术角度解析Office的技术结构。Microsoft的大多数软g的对象结构可以通过Visual Studio提供的工具OLE/COM Object Viewer考察其类型库得到Q通过引用cd库,你甚臛_以得到描q对象信息的C++头文件。这样做真是好处多多。一个典型的Office通常都有一个Application对象Q或其他一个与之相当的对象Q,q个对象相当于Y件枢U,在这里,我们不讨论OfficeQ借此话题说说Application对象。大多数支持扩展QAddin、PluginQ的软g都存在类似的构造。通常Q一个系l得Application对象或者是一个COM对象Q或者是一?NET对象Q如果你的系l存在这cd象,你的pȝ基本具备支持Addin、Plugin的机制了。一个理想的做法是在一个MFCpȝ中,内置一个ATL对象?NET对象Q稍后我们给出方案如何做到这一炏V设计Application对象的关键是如何规划q个对象的属性、方法、事件。如果你希望pȝ具备良好的扩展性,Application对象是十分关键的Q这也是构架艺术的体现。所谓Addin(Plugin)Q是pȝq行时根据需要加载的对象库,Addin(Plugin)之所以可以扩展系l,关键的因素就是系l加载Addin(Plugin)ӞApplication对象传递给Addin(Plugin)库,设想一下,如果Application恰到好处的触发了pȝ事gQ而Addin(Plugin)库如愿的解释了事Ӟ一个Addin(Plugin)库的d不就OK了吗Q因此Application对象是系l设计的关键?/p>
如果你精通ATL对象Q在你的MFCpȝ中添加一个ATL对象Q这个Q务可以用VC Wizard完成。你已经接受了一个事实,是MFCE序中存在一个CXXXApp对象QCWinApp的派生类Q,现在你要做的是增加一个对应得ATL对象。这个对象可以在CXXXApp::InitInstance()中创建,如果ATL对象的类是CXXXAppObjectQ徏议你在CXXXApp对象对象中增加一个成员变量,例如QCComObject<CXXXAppObject>* m_pAppObjQ然后可以入下初始化m_pAppObjQ?/p>
m_pAppObj = new CComObject<CXXXAppObject>Q?/p>
注意E序l束时在CXXXApp::ExitInstance()中释放m_pAppObjQ语句如下:
delete m_pAppObjQ?/p>
你可以将pȝ得关键属性设|成CXXXAppObject的属性,例如pȝ得标题、是否ؓ多文等{。系l希望外部调用的功能可以实现为CXXXAppObject的方法,q一点取决于你的需要。系l需要外部扩展的功能Q表CؓCXXXAppObject的事Ӟ关键是在恰当的位|触发事件以及提供的事g参数。例如,你可以在CXXXApp::InitInstance()触发应用E序开始的事gOnStartUpQPlugin捕获事g后,可以q行特定的初始化Qn份确认、初始信息查询等{)Q你可以在CXXXApp::ExitInstance()触发应用E序l束事gQPlugin捕获事g后,处理用户需要的pȝ退出工作。所有的设计取决于具体设计?/p>
如何加蝲PluginQ是一个有的问题Q如果Plugin实现Z个COM范畴QCategoryQ,可以q用COM技术枚举这个CategoryQ可以将Plugin安装C个特定目录,也可以通过注册表。Plugin的实现可以用COM技术、也可以?NET框架。适当的机会我会提供例子…?/p>
六、后?/p>
一时心血来潮Q就写了q篇文章Q很难说是有心,q是无意。几天前我在新浪|上看应氏杯围棋册Q我觉得该赢了吧Q作Z个围迷Q我们等了十几年Q等C属于国h的应氏杯。记??q前在还在大学工作的时候,有一ơ,一位同事兴致冲冲的走道我面前对我说Q?嗨,昨天马XX赢了李昌镐!"Q当时我在系办公室正在看报纸Q那位仁兄见我头都没抬,非常不满的抢下报U,Ҏ吼道Q?喂!马XX赢了李昌镐!Q你听到没有Q!Q?Q我对他_"你大惊小怪个啥?Q马XX输了李昌镐多盘Q你知道吗?"Q马XX几乎一直在输给李昌镐,Z已经不奇怪了Q偶赢一ơ,国h把他捧得北都找不到了,李昌镐弱?7的时候就傲视q个世界了,可至今面孔不变,几天前的农心杯,中日联军5个hQ被他打个落花流_李昌镐是公认的世界第一Q以至于有的高手知道下一个对手如果是他,׃去订回程机票。这ơ应氏杯Q国人竟然感谢崔哲瀚,何也Q因个弱?9的小子,挡住了他的大哥李昌镐才得应氏杯有了悬念。当国h媒体在说韩国仅李昌镐一人厉害的时候,不知道是Z居心q是自欺ZhQ李昌镐q方30Q不知道要力压中、日多少q_面对q个名字Q真有点L了,q个太极虎!
软g界又来了我们一向不齿的印度虎,2001q我们的软g出口额仅是印度的四十分之一Q我们震惊了Q怎么可能呢?q个四十分之一水分很大Q很可能更可怜!当时我在大连参加一个关?大连软g出口国内W一"的官方会议,那位大h在会上说Q?据说Q我们大qY件出口国内排名第一Q市有关领导希望今天的会议给个第一的数字依据,希望你们把数据报上来Q去q的数据也可xQ注意,我们要的只是数据Q你们仔l体会,我们Ҏ数据Q有奖励Q机会难得呀Q?……。某一天,几个朋友在我家看央视的对话节目,对话一方ؓ国内的Y件大鳄们Q用友、阿派{公司的老MQ,另一方ؓ印度软g的一个代表团。当问及中、印软g差距的时候,我们的刘老总(代表阿尔z)不以为然的说Q据他的看法Q我们已l快赶上Q印度)了,……,a下之意颇有印度的水^不过如此的感觉,印度方的话我至今记忆ҎQ?是否赶上Q国际市的算Q在中国看来Q印度程序员的个性不I技术也不怎么P其实是个错觉Q印度Y仉先注重个性,许多重要的美国商品化软g都是在印度本土开发的…?Q我们的舆论L印度程序员的水qxq的q_xQ可是差距日渐拉开Q……,围棋、球(不好意思谈Q谈不出口!Q、YӞ我们被近ML锁了,乐坏了记者们、给媒体带来了生机…?
日本江户时代的围,如果一个h要想世袭一个称P例如Q本因坊Q,他必L胜所有的师兄弟,然后Q住q师父家的内室,你知道以后的事情吗?以后Q这个棋手,得为师父一家做饭、带孩子、搞卫生……,其余的门人则一心一意的下棋Q这L人、方式,造就了一代一代的本因坊,他们的棋谱大多数都流芌今,q就是早期日本围的悟道模式。Y件d有多语句?我最早接触的计算Y件教材是一本英文版的(影印的D版)Q不同于我们Q那本书的作者构造了"X-语言"Q他们不讲什么C、Pascal、BasicQ一旦缺了什么机Ӟq"X-语言"d些成分。什么C、Pascal、BasicQ你感觉差不多,但现在却分出了等U!我们N语言的能力弱得很Q可是我们在语言的细微之处却很讲IӞ不知道对不对Q许多程序员也许是出于虚荣而用C++Q事实上Q地球h到知道,做数据库QDelphi、VBq比C++胜QQ铺天盖地的C++的书Q写的东西几乎雷同,因ؓQ有用的或者作者不写、或者作者不懂。有时我在想Q如果国内没有内需Q会怎样Q也许Y件内需的存在,造就了中国Y件的特色Q我认ؓ国内业界q没有充分利用中国Y件内需的存在,也许中国软g内需的存在是软g落后的硬伤?/p>
我记得一部电影《神辫》,那个英雄的大辫子被洋人炸掉了Q最l他成了枪手,战胜zh用大刀、秘c是不行的,用洋的东西战胜洋的技术才是正道。我觉得Q一个好的程序员必须了解软g的历Ԍ学习历史Q你知道你ؓ什么弱Q别人是如何强大的。我们正在另一个战Z抗美Q可W的是我们却要赶印度!Q,无论Microsoft、Borland如何争斗Q无Z们谁l治谁,他们不媄响美国的强大Q朋友们Q学习MicrosoftQ开发出让国人感到牛的YӞ