我以 C++ 為基地,遊走於 C#、Java、Objective-C、Ruby……都是在OOP的圈子轉呀轉。
可能是 Apple Mac OS X、iPhone OS 帶起了更多人去做 Cocoa 編程,愈來愈看到 Cocoa Objective-C 的哲學滲入 C++, Java, C# 的世界。
Objective-C 是一種 dynamic binding, typeless 的語言,而 C++, C#, Java 則是 typed 的 programming languages. C++ 的 Boost library 提供了 boost::bind 來盡量模擬 Objective-C 的 dynamic binding。我覺得 Cocoa frameworks 及其前身 NeXTSTEP, OpenSTEP 之所以成功(well, technically, not commercially...)就是因為他是活用 objective-C 語言的 dynamic binding。所以十多年前 Microsoft 在創製他的 MFC 時便引進了 DECLARE_DYNAMIC, DECLARE_DYNCREATE 之類的 macro 來扮演某程度的 dynamic binding.
當然,C++ 始終是 C++,他是 compile time binding 的,不是 runtime binding。所謂的 DYNCREATE 即 dynamic creation,就是今天我們熟識的 factory design pattern. 可是當年連 design pattern 這個 concept 還沒有呢。
在 Java 及 C# 的世界,可以用 reflection 來達成 runtime binding. 將此道運用得出神入化的應該是 Apple WebObjects 了吧。其實, WebObjects 1至4版是 Objective-C 的,5版是把他移殖到 Java,所以把大量的 Objective-C 的風格、編程哲學都帶到 Java 世界。
更有趣的要算是 POCO library。他開宗明義說要成為 C++ 中的 Cocoa frameworks。
可能是《Effective C++》書中所討論的 reference counting smart pointer 跟 std::auto_ptr 的「先入為主」,我一直都搞不清 Poco::AutoPtr 的用法。最近終於搞定了。
《Effective C++》中的 reference counting smart pointer 是自動做 reference counting,而 Poco::RefCountedObject 是手動的。
POCO 的 Poco::AutoPtr 和 Poco::RefCountedObject 是分工的,而且跟 std::auto_ptr 一點關係也沒有,雖然他們都是叫「auto pointer」。 POCO 的 auto pointer 意思是會 auto release 的 pointer。
跟 Cocoa 來作比較便很清楚:
C++:
class Xyz:public Poco::RefCountedObject
{...}
Xyz 是有 reference counting 的功能。Poco::RefCountedObject 只提供 reference counting 的功能。
要 create 一個 Xyz class 的 object instance,用 new:
Xyz *x=new Xyz;
要把 x 殺掉,當然可以用 delete,但也可以用 Poco::RefCountedObject::release()
x->release();
Look! 是不是跟 NSObject 的 retain, release 很像呢?
C++ POCO VS Cocoa:
Xyz *x=new Xyz; ~~~ x=[[Xyz alloc] init]; // reference count = 1
x->duplicate(); ~~~ [x retain]; // reference count = 2
x->duplicate(); ~~~ [x retain]; // reference count = 3
x->release(); ~~~ [x release]; // reference count = 2
x->release(); ~~~ [x release]; // reference count = 1
x->release(); ~~~ [x release]; // reference count = 0 => destroy the object.
而 Poco::AutoPtr 的用法就是要扮 Cocoa 中的 autorelease.
C++ POCO VS Cocoa:
Poco::AutoPtr
x=new Xyz; ~~~ x=[[[Xyz alloc] init] autorelease];