分享
 
 
 

利用using简化受限的proxy代码和调整访问权

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

让我们的一切从代码开始吧,简单起见,代码省略std名字空间:

class MyObject {

object_id obj_id_;

class_id class_id_;

map properties_;

static const type_dict& getDict();

...

};

这是个从实际的项目中整理出来的代码,简单的说明一下:properties存放了Object的属性,MyObject底层依赖一个类型系统的支撑,这个类型系统的模型就是type_dict。class_id_是记录一个对象实例所属的类型,obj_id_则是对象实例的ID.

这个对象的所有属性都是可以从外部访问的,但是,我却不能把properties_公开,因为这样一来的话,外部就可以随便指定一个property_id插入map,而这个property_id也许并没有被当前class_id_所指类型包含,或者,根本就是非法值,这将导致MyObject内部不一致。

于是,除了完成operator[]和clear这样的实现外,我还要这么干:

public:

const_iterator begin() const{ return properties_.begin();}

iterator begin() { return properties_.begin();}

...

他们的实现都很简单,只不过是一行:调用properties的相应方法就是了,可我不得不重新写一遍,这是个copy&paste工作,总是让我想打瞌睡,结果,我总是出错,因为我总是忘记做一些必要的修改。如果有类似这样一种语法:

public:

proxy const_iterator properties_.begin() const;

或者:

proxy properties_.end;

我想我会愉快的多。除了少些一些代码外,关键是代码变得清晰了,程序员通常都是懒惰的,要命的我既懒惰又健忘,保持代码清晰对我而言很重要。于是,代码变成了这样:

class MyObject : private map {

typedef map ContType;

object_id obj_id_;

class_id class_id_;

//map properties_;

static const type_dict& getDict();

...

};

然后,我可以这么写:

public:

const_iterator begin() const{ return ContType::begin();}

iterator begin() { return ContType::begin();}

这样看上去语义至少清楚了一些,可是仍然不能让我满意,那个return 语句我还是可能弄错:我把上面两句c&v,然后把begin改成end,结果改漏了一个:(

最终,using达到了我的目的,我决定这么写:

public:

using ContType::begin;

using ContType::end;

using ContType::insert;

这么写不会导致访问权的问题,看,这和我最初设想的proxy properties_.end;多么相似。这样写的好处不仅仅是简单,最重要的是表达出来的语义:转调容器的相同方法。我想任何程序员首先都会相信STL的方法,而不是我写的,即使我的代码只有一行,也可能出错。using 方法如果出错的话,编译时就不会通过。

再想想,using 只是引入一个名字,那么using对typedef的别名应该也有效。来让我们试试这个:

using ContType::iterator;

很好,它可以工作,而且还不必像typedef那样在ContType::iterator前面加一个typename.于是,我决定把map内的类型申明用using的方法引入到MyObject中来,有十几行代码。还好,和using一个成员函数一样,using后面拼写错误的话,编译器立刻就会报错。

我似乎把这个问题解决的很好了,只是还有一点小麻烦:我代理了大部分map的方法,引入map的typedef。其实只有map的swap、operator[]等等少数几个方法需要修改,可是我却要为其他部分写上几十行代码。回到我的目的上来:我只是要防止某些外部对MyObject的修改,避免导致内部不一致而已。结果,我不得不把一大堆typedef和const方法也using了个遍。增加了代码长度倒是其次,它扰乱了我的视线。直观的,别人会以为我是因为需要这些方法,所以代理了他们,但真实的涵义却是:我不关心他们(像count这种东西,我真的不知道是不是需要暴露出来),所以还是让他们保持原样。这种直观的隐喻和真实意图之间的矛盾,让我担心总有一天他会骗倒某个人。还有更好的办法吗?

再让我们看这样一段代码:

struct A{ void fun(){} };

class B : public A { using A::fun;};

试试这一句:B().fun();

编译出错!报告不能访问私有成员。这意味着我们我们能够改变一些基类成员的访问权!实际上,这种访问限制既可以放宽,也可以加强,这太好了!于是我的MyObject可以变成这样:

class MyObject : public map {

typedef map ContType;

using ContType::operator[];//这里,禁止访问map的clear和operator[]

using ContType::clear;

public:

void clear();

...

};

虽然我在public中也定义了void clear(),但这和悄悄的覆盖行为不同,using ContType::clear; 强烈的表达出关闭基类clear的语义。

这种方法我只需要写几行代码,而且更容易让我们的视线集中,还可以偷更多的懒。

这里有个小小的不足,如果我用MyObject().map::clear()这样的方法,就可以合法的调用map::clear了。不过这基本上可以认为是hack手法,不必过分去关心的。

using在这里很好的解决了我的问题,然而,他还是不能取代proxy。using无法让我有选择的代理函数的特定重载版本,例如我想公开const_iterator begin() const;而不公开iterator begin()就不能通过using实现。真希望C++会在语言层面支持proxy、delegate、reflection这样的特性,但是这种期望是在是不令人乐观。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有