免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: art_codes
打印 上一主题 下一主题

[C++] 确认一下c++中不能使用interface(如java)那样的功能把 [复制链接]

论坛徽章:
0
371 [报告]
发表于 2009-03-28 14:17 |只看该作者

回复 #372 bohemia 的帖子

引用 flw 的一句话:tools shape thoughts.

论坛徽章:
0
372 [报告]
发表于 2009-03-28 15:13 |只看该作者
我爬到这里来了……不容易

对了对于刚才那个正方形不能派生自长方形的问题大家能聊聊了? 我感觉很有意思(竟然以前都没听说过,日)

论坛徽章:
0
373 [报告]
发表于 2009-03-28 15:21 |只看该作者
原帖由 langue 于 2009-3-28 14:17 发表
引用 flw 的一句话:tools shape thoughts.


用了C#,脑袋会变方

论坛徽章:
0
374 [报告]
发表于 2009-03-28 15:23 |只看该作者

回复 #376 reiase 的帖子

你说的那个事实,应该叫 tools shape your brain/head.

论坛徽章:
0
375 [报告]
发表于 2009-03-28 15:58 |只看该作者
原帖由 reiase 于 2009-3-28 15:21 发表


用了C#,脑袋会变方



有这个意思.哈哈

论坛徽章:
0
376 [报告]
发表于 2009-03-28 16:19 |只看该作者
我提一个意见啊,  你看对不对。
这2个回调函数, 是否应该这样才比较合理???

int (*hashfun)(const void *key, const void* user_data);
int (*hashcmp)(const void *lkey ,const void *rkey, const void* user_data);


这种设计的确功能更强大,但不符和大多数人的习惯,
无论sgi 还是vc 的stl map/set ,都是提供了最少的参数列表。
而且你的例子属于非正常情况,对sort情况可能比较适合,

我觉得,在设计中:
遇到非正常情况,应保证用户自己可以通过非正常方式解决
但不应单单为了照顾非正常情况,引入非正常的接口。
(stl 的 sort 应该也是基于这种考虑的吧)

[ 本帖最后由 windyrobin 于 2009-3-28 16:22 编辑 ]

论坛徽章:
0
377 [报告]
发表于 2009-03-28 16:32 |只看该作者
原帖由 windyrobin 于 2009-3-28 16:19 发表


我觉得,在设计中:
遇到非正常情况,应保证用户自己可以通过非正常方式解决,
但不应单单为了照顾非正常情况,引入非正常的接口。


精辟阿

论坛徽章:
0
378 [报告]
发表于 2009-03-28 20:03 |只看该作者
c++如果真得达到了所谓开发效率和执行效率的平衡点,java可能就不会发展成今天这样了。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
379 [报告]
发表于 2009-03-28 22:59 |只看该作者
原帖由 flw 于 2009-3-28 10:24 发表

这个在 FP 中很正常,因为很容易解决


flw大大所说的FP是 Functional Programming 还是 Fact (Oriented) Programming??
应该是前者吧???

很容易解决, 应该是指它们都支持curryingpartial application吧???


比如我上面举的例子:

typedef enum course_category_ {
  chinese,
  math,
  english,
  /* ... */
  course_category_end,
} course_category;

typedef struct student_ {
  const char* name;
  int marks[ course_category_end ];
} student ;


现在假设需要利用qsort实现一个函数 :
void sort_by_cours(student students[], size_t count, course_category category);


但是要比较某一科目的成绩, 需要3个信息, 才能完成工作。
int cmp(course_category c,const void* s1, const void* s2) {
  return ((const student*)s1)->marks[ c ] - ((const student*)s2)->marks[ c ] ;
}

但这个函数却不是qsort能够接受的回调签名


利用functional programming中的partial applicaton的理论(假设c语言支持它们), 是否就可以这样实现 ?
void sort_by_cours(student students[], size_t count, course_category category) {
   papply = curry( &cmp ) ( category );
   qsort(students, count, sizeof(students[0]), papply );
}



可是, c语言中并不直接支持currying与 partial application ……

实际上, 我目前正在做这个工作 ……  为c函数提供partial application支持
项目在这里 : http://code.google.com/p/callback-currying/

支持 cdecl 和 stdcall 两种调用约定。
已经在x86上的xp sp3, ubuntu8.04 , mac os x 10.5.6上进行过测试。

[ 本帖最后由 OwnWaterloo 于 2009-3-29 00:30 编辑 ]

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
380 [报告]
发表于 2009-03-28 23:37 |只看该作者
原帖由 windyrobin 于 2009-3-28 16:19 发表
无论sgi 还是vc 的stl map/set ,都是提供了最少的参数列表。
(stl 的 sort 应该也是基于这种考虑的吧)


我觉得不是这样。

支持回调模式的技术有很多, pointer to function, functor, interface, delegate, signal/slot 等。
pointer to function和其他的技术有非常重要的不同 —— 被指向的函数, 不含有状态(或者叫信息)
而其他技术, 加入信息是很容易的。


比如我在上一楼又复述了一次的例子, 如果使用std::sort 而非qsort, 就可以很容易加入额外信息, 比如:

class sort_by_course : public std::binary_function< student, student, bool > {
   course_category c_; // 包含额外信息
public:
   explict sort_by_course(course_category c) c_(c) {}
   bool operaotr() ( const student& s1, const student& s2) const {
      return s1.marks[ c_ ] < s2.marks[ c_ ]; // 使用额外信息
   }
}

void sort_by_course( student students[], size_t count, course_category category ) {
  std:: sort( students, students + count, sort_by_course( category /*插入额外信息*/ ) );
}

如果利用boost:: bind 或者lambda表达式, 可以做得更漂亮一点。



但是, pointer to function不行, 它不含有状态。
而且, 无论是stl的bind机制, functor机制, 还是boost的bind机制, lambda表达式(或者是c++0x直接支持的),都不能提供帮助。
因为, 它们产生的闭包只能被函数模板所接受, 不能当作一个函数指针传递给qsort。


所以, 我觉得, 一个设计良好的回调函数, 其签名, 应该带有维持状态的参数
这样, 按照该签名实现的回调函数,其功能才是完备的。



原帖由 windyrobin 于 2009-3-28 16:19 发表
我觉得,在设计中:
遇到非正常情况,应保证用户自己可以通过非正常方式解决,


我们来看看能够怎样解决那个问题。  我还是用 sort_by_course的例子可以吗?
http://code.google.com/p/callback-currying/ 中有一个sort_by_course的sample。

1. 很容易想到的就是, 为每一个特定的比较, 实现一个函数 :
cmp_chinese, cmp_math , cmp_english ....
然后 sort_by_course  中用一个表, 或者switch。
( 见sample中的 similar_comparison

这样的问题是, 重复。 每一个函数除了缺失的category, 其他部分都是相同的。
重复会导致的问题就是, 一处修改, 处处修改


当然, 对这个简单的例子, 它应该是不用修改的。 实际情况它也许比较复杂。
对于这种比较准则的回调函数, 也不应该有太复杂的逻辑。
如果我们不仅仅讨论比较准则, 而是讨论回调函数应该如何设计,适用性才更广泛, 就假设回调逻辑会变得很复杂吧 ……


2. 如何避免重复 ??
在sample中, 有另外2个 similar_comparison_by_macro similar_comparison_by_template
分别使用了宏和模板来消除重复。


3. 这样还有问题 : 源代码没有重复了, 函数体仍然有重复
最终包含的机器码的大小和b]similar_comparison依然是没有区别的。

如果我们仅仅使用一个
int cmp_generic( void* user_data, const void* s1, const void* s2 ) 来实现回调逻辑。
那么, 比较逻辑就只有一份机器码了。 (再次说明, 假设回调逻辑会变得很复杂)

然后为cmp_chinese, cmp_math , cmp_english .... 分别实现成短小转发函数
qsort 最终接受的是上面那几个转发函数。

这样就将重复减少到最小

具体见sample : forwarding_function, forwarding_function_by_template


3. 当然, 也可以使用全局静态变量。
这可能是最快速的解决方法了。 这个就没有sample了。

但是, 全局静态变量也有一些问题 :
多线程?  要使用线程局部存储。windows我知道是支持的, linux我不了解了……

而且,有个最严重的问题
在qsort中不能体现出来(所以没有为全局静态变量这个方案做sample)。(但是如果要写能体现出这个问题的sample, 又肯能会复杂得不适合做sample)
——如果你不知道回调函数的被调用时机, 全局静态变量的方法就不能使用。
比如 : WndProc (真是一个糟糕的设计 ………………)



那么, 对于一个比较通用的回调函数设计(不仅限于比较准则), 是否应该带有状态维持参数, 才是良好的设计??
想想 WndProc , HookProc为我们带来了多大的麻烦 …………


原帖由 windyrobin 于 2009-3-28 16:19 发表
但不应单单为了照顾非正常情况,引入非正常的接口。


恰恰相反。 我觉得加入维持状态的参数, 才是正常情况
不使用这个参数, 才是非正常情况

不使用这个参数, 一般只能完成一些很简单的工作。
比如还是那个项目中, 有一个自己捏造的 retrieve的sample。
设计的回调函数签名如下:
int ( stdcall * retrieve_fn)( node* );
这即使一个不带状态维持参数的回调函数签名
在这种设计下, 仅能实现一些很简单的工作,  见 simple_task
全局静态变量是一种解决办法,( 见 simple_variable), 同时,也不会出现上面说的严重问题——不知道被调用的时机。
全局变量么 …… 总是能避免就尽量避免吧 ……



这样的接口, 对于hash map的是否合适, 决定权还是在你手上, 我只是提个建议。
不, 建议都算不上,  我只是有点疑问 …… (因为我确实不懂, 没有大量使用hash map的经验), 还请指教。
这样的接口, 真能满足所有需要吗?  或者, 大部分的需要吗?

如果你所说的非常规情况会出现得很多吗?
出现了,  能很方便的处理吗?

[ 本帖最后由 OwnWaterloo 于 2009-3-29 00:51 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP