免费注册 查看新帖 |

Chinaunix

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

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

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
91 [报告]
发表于 2009-03-30 22:17 |显示全部楼层
原帖由 shan_ghost 于 2009-3-30 11:38 发表
一切都是文件
至于具体细节,另外用特定的xxctl微调一下即可


既然一切都是文件, 为什么还需要用xxctl微调?
还不是因为C无法很自然的表达一切都是文件的概念。


原帖由 shan_ghost 于 2009-3-30 11:38 发表
既然OO只和设计有关,那么虚函数表是什么?


是,你说的非常对!虚函数表确实和OO的本质没有一丁点儿关系
C++、java、C#中使用OO, 根本无需关心虚函数表

反到是用C实现OO的时候,再不断的考虑这些东西手工模拟这些东西


原帖由 shan_ghost 于 2009-3-30 11:38 发表
换言之,他们学的是某种特定的OO协议,而不是OO本身。


那么,你说的他们, 是否是通过C学习OO的人?




原帖由 shan_ghost 于 2009-3-30 11:38 发表
更有甚者,和高明设计所作出的自然而然的约束不同(就好象大自然约束我们永远不能超过光速一样),OO语言是靠着硬性规定来约束程序员
不违反接口约定的。


为了保护这些约束不被违反,OO语言引入了“权限”语义(这方面矫揉造作的例子一时还没想到特别典型的)
为了用户能定义自己的约束,比如对于“必须自己给出具体实现”这个约束,C++语言加入了纯虚函数,Java搞了个接口类(interface)
为了在用户瞎搞的情况下不产生内在冲突(如菱形继承),如Java等语言禁止了多重继承。
为了防止过分的保护约束住用户的手脚,它们又搞了很多类似RTTI的东西,以便让用户在封装上掏窟窿……



当C写下
struct x_handle;
struct x_handle* x_create(void);
/* more... */
的时候, 算不算用户自定义的约束???

写下
struct file_ops {
  int (*open)(int fd ... );
  /* ... more */
};
这又算不算用户自定义约束???

当写下:
#define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name
这又算不算用户自定义约束???



原帖由 shan_ghost 于 2009-3-30 11:38 发表
RTTI又算什么?



不知道你所说的RTTI是指什么。
我只说它的一个作用, 安全转型


然后我们再来看安全转型(分2种)是否必要

首先,单继承下的向下安全转型,也许通过重构,单继承下的向下转型是不需要的。



但是不要忘了, 还有多继承(注意, 也包括单继承多实现这种受限多继承模式)下的横向安全转型

class C : I1, I2, I3, I4 , ... In  {};
一个实现了若干接口的类。

当你使用其中一个接口的时候, 这个类也是其他接口的类型信息就丢失了, 只能通过RTTI找回来
这在.Net中是必不可少的事情, 因为.Net可以进行COM开发。
而COM的QueryInterface做的就是的接口查询 —— 横向转型

以下代码是在COM开发时的常见代码:
I1 i1 = getI1();
I2 i2 = i1 as I2;
I2 i2 = (I2)i1;
if (i1 is I2 );

后3句如果没有RTTI该如何实现???

同样, 这些语言屏蔽了这些细节。 而C语言却需要手工实现这些细节。



论证到此:
可以说RTTI的需要是因为多继承(包括单继承多实现这种受限模式)的需要
而多继承是否必须?
我没有开发大型OO系统的经验, 不知道这种横向转型是否能通过重构完全消除掉
至少在COM中, 目前是需要这种能力的。


同样, 这些语言(C++、java、C#)给你一种方式去执行横向转型。 你可以完全不知道这是RTTI的情况下去使用它们。
反而是C, 如果需要支持这种设计, 要自己模拟RTTI



原帖由 shan_ghost 于 2009-3-30 11:38 发表
公有/私有继承又是什么?


这确实是C++独有的一个问题。
私有继承至少有2个用处:


1. 它支持如下表达 :

一个采用了Template Method模式的类。
它有一个虚函数(甚至是纯虚), 由子类去定义。

class C {
public:
  void useful() {
    // pre code
    do_useful();
    // post code
  }
private:
  virtual void do_useful() = 0;
};


一个子类:
class D : public C {
  virtual void do_useful() { /* ... */ }
// ...
};

那么, 就可以这么使用 :
D d;
d.useful();
C& c = d; // ok

但你又同时不想表达 D is-a C (或者说想禁止这种关系), 就要
class D1 {
  D d;
public:
  void useful() { return d.useful(); }
};
D1 d;
d.useful();
C& c = d; // error


而私有继承可以一步到位
class D : private C {
  virtual void do_useful() { /* ... */ }
public:
  void useful() { return C::useful(); }
};

D d;
d.useful();
C& c = d; // error



2. 它支持空基类优化这确实和OO没什么关系

namespace std {

template<typename T>
class allocator { };

template<typename T,class A=allocator<T> >
class vector {};
}

vector 必须实现一个 allocator<T> get_allocator() const; 的函数。
如果将allocator<T>作为成员(它通常是一个空的), 将多占用4字节。
而继承至一个空类, 在编译器上可以执行空基类优化, 可以去掉这多余的4字节。
同时, vector又不是一个allocator, 所以用private继承。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
92 [报告]
发表于 2009-03-31 11:03 |显示全部楼层
原帖由 shan_ghost 于 2009-3-31 10:29 发表
你真的理解了什么叫RTTI吗
COM的QueryInterface是为了和其他语言在二进制层面上兼容而设。


首先, 是你没有说明RTTI这个宽泛的术语,  究竟是指的什么。
所以我才开始推测, 你指的究竟是什么。

COM的QueryInterface的目的是什么? ——  接口查询。
二进制兼容的目的是什么?   —— 为不同语言, 提供一个相同的接口查询方式

如果仅在C++中, 因为有C++的RTTI(你仅指这个?), 所以根本不需要COM那一套。完全可以用语言内建设施来完成。
在java、C#中也是如此。

在这些直接支持OO的语言中,完成接口查询是很自然的事, 根本无须关心是否有RTTI的存在是否有元数据


仅在C中, 需要手工实现(叫RTTI也好,叫元数据也好,总之你得模拟出一套机制,一套和OO本质无关的东西),来实现: 接口查询。

同样, 还是在C中, 更偏离了你所谓的OO的本质。


原帖由 shan_ghost 于 2009-3-31 10:29 发表
你真的理解了什么叫RTTI吗
1、我不挑剔各种OO语言的协议实现,因为我知道该如何取舍它们。


嗯, 你牛, 你知道如何取舍, 所以你提倡手工实现这些细节, 对么?


原帖由 shan_ghost 于 2009-3-31 10:29 发表
你真的理解了什么叫RTTI吗
2、我不认为某语言特定(或被公认有效而通用)的协议实现就是天经地义、不可更改的——比如禁止不紧张多继承;提供/不提供元数据和RTTI等等。


我从来没说这些是天经地义的。
只是有人喜欢以自己的方式去手工模拟一套。

原帖由 shan_ghost 于 2009-3-31 10:29 发表
3、C++是一个很好的工具箱,但修理手表的时候我不认为有把锤子拿出来的必要。


C同样是一个很好的工具箱, 但狙击1500米外的敌人的时候, 请不要使用手枪。


原帖由 shan_ghost 于 2009-3-31 10:29 发表
4、你有了一匹好马,所以最好配个好鞍;你有了好鞍,所以要有把好剑;你有了把好剑,所以需要一副盔甲;你有了沉重的行头,所以需要另一匹马帮忙运送装备,于是你又需要一个仆人来帮忙牵马,还得找个马夫来照料它们;人多了,衣食住行都得靠你,于是你又不得不再买辆马车;买了马车,为了配上你华丽的长剑,你又需要漂亮装饰品……………………………………

天哪,孩子,咱村人让你牵马过去磨点面,好让大家中午填饱肚子,谁知你这一去好几十年……


你有一身好武艺, 飞天遁地无所不能。
你可以在村里,在乡亲父老们面前秀秀身手。
但你终究是肉身, 不要拿着大刀出现在现代战场上。

[ 本帖最后由 OwnWaterloo 于 2009-3-31 11:10 编辑 ]

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
93 [报告]
发表于 2009-03-31 11:44 |显示全部楼层
原帖由 shan_ghost 于 2009-3-31 11:15 发表
事实上,我以为一切讲解C的OO实现或汇编实现OO的书,在项目设计角度看,都是垃圾。
好的设计只有一条路:抓本质。
所谓的OOC之类东西,根本就不研究上面的本质性问题,而是哗众取宠般的去用C模拟C++的某些特性


我的观点不正是这个么。

不过我还不敢像你那样, 直接说这些是垃圾 ……
研究即可,  具体是否实用,  要看环境 ……

原帖由 shan_ghost 于 2009-3-31 11:15 发表
模拟OO协议的无聊家伙是有——他们才是C++中毒最深的重度患者,以至于以为OO就是C++那套协议,得用C原汁原味的模拟出来。

这关C++什么事 ……
我不是一直在反对模拟OO的特性, 反对窥视OO具体实现, 支持直接表达OO思想么 ……


原帖由 shan_ghost 于 2009-3-31 11:15 发表
作为同样的OO协议中毒患者,你看不透这点很正常。这里只是提醒下,不要把任何人都想成是脑子里有个框框、以至于脱离了C++风格的OO协议就活不下去。
阁下不妨看看GTK,看里面是怎样实现自己的OO协议的。


只是有人提到了用C去实现那套协议,  我才想与之讨论一下 :
是C++提供的协议更自然,更能表达OO本质, 不涉及OO的细节, 还是C模拟出的那一套更自然,更能表达OO本质,又不涉及OO细节。


GTK+ 我没用过……
GTK么 ……  看着那一堆MACRO ……  这又算不算心智包袱?



同样, 杀敌是目的, 应该选择适合的手段。

[ 本帖最后由 OwnWaterloo 于 2009-3-31 11:50 编辑 ]

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
94 [报告]
发表于 2009-03-31 12:05 |显示全部楼层
原帖由 shan_ghost 于 2009-3-31 11:30 发表

1、元数据和RTTI之间是一个包容关系,但究竟是谁包容谁,你知道吗?


一部分元数据的目的, 是为了鉴别对象的类型, 这部分被赋予了一个专有的叫RTTI的名词。
所以我才在仅在C++中使用RTTI这个术语。
而在java和C#中使用元数据, 他们的元数据部分是为了鉴别对象类型, 其他部分还能做更多的事。


是你在上面帖子中提到 :
1. 在设计时,不应该考虑RTTI这些事情。
2. 大部分使用RTTI都是不合理的。

我的回复只是说明 :

1. 在单继承下, 也许使用RTTI确实不合理。
2. 在多继承下, RTTI应该是必要的措施。
3. 在C++中, 可以不去理会RTTI这种细节,  直接做自己想做的事 : 接口查询。
4. 在C中, 要手工模拟该功能。




原帖由 shan_ghost 于 2009-3-31 11:30 发表
2、元数据的格式有统一规定吗?尤其是在跨语言使用时?
3、即便是在C++中,COM也不得不抛弃了RTTI,自己从头实现元数据——我不知道你装出一副义正辞严的样子是为了说明什么。


不知道你所谓的“义正词严”是指的什么。

我举COM, 是为了说明 :
1. 这是一个需要接口查询的实际例子。
2. COM手工生成 ( 硬编码 ) 用于RTTI的元数据。
3. COM是对为了跨语言使用C++, 而对C++的RTTI进行扩充。 如果仅在C++中, 接口查询的事可以使用C++本身的机制可以做得很好。



这些也同样是为了说明, 在直接支持OO的语言中, 才能较少直接处理与表达OO思想这一目的无关的东西。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
95 [报告]
发表于 2009-03-31 12:45 |显示全部楼层

回复 #406 flw 的帖子

flw大大能回复一下我在39页, 382楼的帖子么?
谢谢~~~

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
96 [报告]
发表于 2009-03-31 12:55 |显示全部楼层
原帖由 shan_ghost 于 2009-3-31 12:49 发表
呵呵,选择性无视——“义正辞严”当然指的是你莫名其妙对C “模拟元数据”的讨伐,却无视C++实现COM同样也要“模拟元数据”。


C和COM是手动, C++是自动。

手动,表达了与思想无关的东西。
自动,直接表达思想。

你不是说  要抓住思想,这个本质么。
所以我才说这个。

居然被你理解成莫名其妙的东西 ……

[ 本帖最后由 OwnWaterloo 于 2009-3-31 12:58 编辑 ]

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
97 [报告]
发表于 2009-04-09 14:19 |显示全部楼层
本来见这帖子沉了 ……  就算了 ……  结果又被顶起来了 ……

原帖由 reiase 于 2009-4-9 13:04 发表
在A库中被实例话foo<int>,在B库中也实例化foo<int>.因此A,B中各有一份实例化的foo<int>,我搞不懂同时连接A,B两个库时咋办,连接器不会报错吗?


简单的说, 没有二进制的模板库, 模板库都是源代码级的。
目前支持export的编译器依然需要源代码。

通常不会将模板、 类、 异常这些东西从库中导出。
导出的只是函数+基本类型, 也就是C接口。
因为C++没有二进制标准。  其实这是我对C++最不满的地方 ……  许多时候都麻烦死 ……


从库中导出C++的东西, 通常只是为了方便, 不是为了发布。
比如, 把boost中的某些东西, 编译成库, 省去每次都再编译的时间。

如果打算发布C++的binary库, 就必须给不同编译器上的不同版本分别编译出一个二进制库然后发布。
这就将开发库的编译器(包括一些编译选项)和使用库的编译器绑定死了。


原帖由 reiase 于 2009-4-9 13:04 发表
连接器不会报错吗?或者说编译器为由模板实例化的函数自动添加static内部连接属性,这样不会造成二进制文件体积爆炸式膨胀吗?这个问题还真搞不懂,请你指点了


链接器当然不会报错,  你用过模板的吧?
具体的作法C++标准没有规定。

你说的这个是一种方式, 对每个翻译单元, 都暴力编译一次。
但是最后链接的时候, 将重复的副本删除。

这几天我做了一些测试, 不过数据太多, 需要整理整理 ……

大致结论就是, 编译器确实会删除这些副本, 只留下一个模板实现代码。
测试环境有这些 :
msvc8、 gcc (GCC) 3.4.2 (mingw-special),gcc (GCC) 4.2.4 (Ubuntu 4.2.4-1ubuntu3)

抑制代码膨胀, 编译器方面是做了工作的。
剩下的工作就是模板的编写者了。

这个是指导方针 : “C++箴言:从模板中分离出参数无关的代码 ” http://dev.yesky.com/392/2249392.shtml


还有一个结论,  编译确实很慢 ……
500行不到的东西, 需要要编译7分钟 ……


俺前边提到过超线性并行受益吧,我觉得既然有些优化是不可能在编译时进行的,这里也存在一个超线性的问题,没准会超过C++.参考前边说过的那个脚本语言快过C++的例子

原帖由 reiase 于 2009-4-9 13:04 发表
俺前边提到过超线性并行受益吧,我觉得既然有些优化是不可能在编译时进行的,这里也存在一个超线性的问题,没准会超过C++.参考前边说过的那个脚本语言快过C++的例子


在这点上, 我觉得被你忽悠了 ……
另外一楼中再请教你

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
98 [报告]
发表于 2009-04-09 14:40 |显示全部楼层
原帖由 reiase 于 2009-4-9 13:04 发表
其实,每种语言在选择特性的时候,都要面对一个机会成本的问题。也就是,选择了特性A,那么因此带来的性能开销叫做性能成本;如果选择了A之后无法再选择B特性,那么B要和A的性能开销一起算进A特性的机会成本里边去。

某些人一直强调C++的性能开销如何如何小,却一直不承认C++那个机会成本高的现实。而且随着技术进步,讨论机会成本的语境也在变化,这也是python,ruby等以前认为机会成本很高的语言,现在被普遍接受的原因。而C++却是随一些技术的成熟,机会成本变高的那一类语言。不信去看看C++09的一些提议,绝对是针对这一点来的


哪些提议???


你指的机会成本, 就是C++的动态优化几乎被禁绝了, 是吧?
先说说那个函数式编程的脚本语言, 效率超过C++的问题。  我又仔细想了想, 觉得是彻底的被你给忽悠了。

原帖由 reiase 于 2009-4-9 13:04 发表
foo(x)这个函数,在函数式语言里,只要参数相同,返回值就一定固定。而在C++里边,有前边所讲的,函数返回值是状态相关的,因此,不能断定相同参数下,返回值就一定相同。所以对foo(foo(foo(...)))这种表达式,在函数式语言里,可以在编译时就求值,而C++里是万万不行的,所以某些函数式的脚本语言,是能够在特定应用场合下具有超越C\C++的性能的


几个问题,
1. 这是编译型语言, 还是解释型语言?
2. 如果是编译型, 这个优化是运行时, 还是编译时?
3. 如果是编译时, 对优化就只能是常数??

比如,
f(f(f( 1 )));  这个可以?

那么, C++里面, 这个优化同样是可以做的。

f(n) {
  if (n==0 || n==1) return 1;
  return f(n-1) + f(n-2);
}

template<int n>
struct f {
  enum { result = f<n-1>::result + f<n-2>::result };
};

template<> struct f<0> { enum { result = 1 }; };
template<> struct f<1> { enum { result = 1 }; };

enum { final_result = f< f< f<1>::result >::result >::result };
注意, 这同样是一个编译时常量。 比如, 可以作为数组的维度(C++不支持variable length array)
char a[final_result];


---------------------------------------------------------------------------------------------------------
那么, 这个又可以吗?
var v = read();
f(f(f( v ) ));    而且是编译时求出结果??

显然不可能吧?  v 的值都未知。


那么, 如论它是编译型还是解释型, 都是运行时作的优化, 而且优化的本质, 就是一个缓存机制而已。
那么, 该语言如何知道, 那些函数应该缓存其值?  哪些函数不应该缓存其值?
对要缓存其值的函数, 缓存应该保留多久???
如果它盲目的对所有函数都进行 ( 参数 => 结果 )的缓存, 效率不见得会提高。
在这种语言中, 是否有什么机制通知语言, 对哪个函数、 何时开启这种优化?


算法比赛的时候, 同样有一种方式, 叫记忆化搜索。
当“人眼”看出, 某个函数的定义域和值域的取值集合可接受, 就可以启用这一方式。
对同一个值, 同样不会求值第2次
只要参数相同,返回值就一定固定”   从某种意义上来说, 这是函数式语言的特点, 但更是问题的特点。
只要问题满足这个条件, 并且定义域和值域的取值集合可接受,  任何语言都可以手工启用优化。


函数式语言无非是将这个自动化而已。 那么, 如果它真能达到和人一样的判断, 当然是好的, 问题是它达得到吗?
是否动态优化就目前来说, 应用范围依然是狭窄的???
依然要来判断, 何时应该使用何时不应该使用?

[ 本帖最后由 OwnWaterloo 于 2009-4-9 14:48 编辑 ]

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
99 [报告]
发表于 2009-04-09 14:53 |显示全部楼层
原帖由 emacsnw 于 2009-4-9 12:27 发表


设计模式里面提到过两个概念:type和class。
type是一个类的接口,class是它的实现。
C++把type和class通通揉到一个叫做 "class" 的单元里面去了,所以不能完全描述 interface 这样纯 type 的概念。


确实, C++中, class代表了很多毫不相干概念。

但是, 不同于java、C#, C++把兼容于C放在很重要的位置, 没办法自由添加关键字

BS在关键字上是经过很多思量的。
比如他还想把  throw try catch 缩减到 try catch。 catch 同时表达目前throw 和 catch的含义。
目的就是为了减少一个关键字, 减少和现有C代码的冲突
要他真要这样做, 估计在这点上又会被人骂了。


type这种东西 ……  估计在C代码中到处都是, 显然不能用来做关键字。

[ 本帖最后由 OwnWaterloo 于 2009-4-9 14:54 编辑 ]

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
100 [报告]
发表于 2009-04-09 14:57 |显示全部楼层

回复 #419 flw 的帖子

其实我也不懂 ……  我只是想了解一下这几个术语是否使用得当 ……

很多时候, 争论都是由双方对术语理解有差异造成……
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP