var arr = [new A(), new B(), new C()];
我经常使用javascript这类脚本语言的容器感觉很方便和拥有更好的运行时容错。
然后一个简单的数组可以连续放置多种类型对象,在弱类型脚本语言的世界这是符合世界观的。
接下来静态类型的语言的话能不能做到类似的效果呢?当然是可以的,这句是废话,不然没法继续写了。
对于支持契约(比如java)编程的静态语言我们可以把容器的类型定义为接口类型, 这相当于通过契约拥有一部分的动态能力。当然这个不在我们的探究范围内 OMG。
接下来事情是如果我是要用c++呢?
随即我命了一个命题:现在拥有一个JSObject的基类,下面派生出的JSSring和JSArray两个子类,把他们 放进同一个容器里。按照书上代码敲完,我发现c++在做这事的时候显得有些僵硬的可以。
代码如下:
namespace client {
class JSObject {
public:
virtual JSObject* copy() const = 0;
virtual ~JSObject() {};
virtual std::string toString() = 0;
};
class JSObjectProxy {
public:
JSObjectProxy();
JSObjectProxy(const JSObject& );
~JSObjectProxy();
JSObjectProxy(const JSObjectProxy &);
JSObjectProxy& operator = (const JSObjectProxy &);
userdata
std::string toString() {
return obj->toString();
}
private:
JSObject * obj;
};
JSObjectProxy::JSObjectProxy():obj(0) {}
JSObjectProxy::JSObjectProxy(const JSObject &v) :obj(v.copy()){
}
JSObjectProxy::~JSObjectProxy() {
delete obj;
}
JSObjectProxy::JSObjectProxy(const JSObjectProxy &v):obj(v.obj?v.obj->copy():0) {
}
JSObjectProxy & JSObjectProxy::operator = (const JSObjectProxy &v) {
if(this != &v) {
delete obj;
obj = (v.obj?v.obj->copy():0);
}
return *this;
}
class JSString :public JSObject {
public :
JSString() {}
virtual ~JSString() {};
virtual JSString::JSObject* copy() const {
return new JSString;
}
virtual std::string toString() {
return "JSString";
}
};
class JSArray :public JSObject {
public :
JSArray() {}
virtual ~JSArray() {};
virtual JSString::JSObject* copy() const {
return new JSArray;
}
virtual std::string toString() {
return "JSArray";
}
};
}
测试的代码如下:
using namespace std;
int main() {
cout << "this mode is x86" <<endl;
client::JSObjectProxy arr[2];
client::JSArray a;
client::JSString s;
arr[0] = client::JSObjectProxy(a);
arr[1] = client::JSObjectProxy(s);
cout << ((client::JSObjectProxy) arr[0]).toString() << endl;
cout << ((client::JSObjectProxy) arr[1]).toString() << endl;
return 0;
}
总之在我们享受这种方式带来的便捷后, 一定要清楚使用这种方式后的边界在哪里, 而不是一味的去贪图习惯和便捷。