找回密码
 FreeOZ用户注册
查看: 1542|回复: 5
打印 上一主题 下一主题

[论坛技术] C++的三种继承类型问题

[复制链接]
跳转到指定楼层
1#
发表于 11-5-2009 13:10:11 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?FreeOZ用户注册

x
继承是面向对象的主要特征之一(另一是封装),我们的直觉概念中,继承实现了一种is-a的关系。
然而,由于C++中提供了很灵活,甚至有点自相矛盾的继承实现,使得我们不得不小心应对。

1. public继承时删除某些操作。
一个父类中的某个操作,当你不希望被人在子类中调用它时,可以通过显式设置其private范围描述字
而取消它的外部使用权限。但是,如果client是通过父类进行调用,则这种设置就没有任何用处了。
很有一种防君子不防小人的感觉。

2. private继承与组合
  private继承实现的是一个has-a的模型,而不是is-a模型。所以,如果只是考虑重用而使用了private
继承,应该当机立断改成组合。
  在《C++编程惯用法》第4章70页中提出一个例外的情况,可惜这个问题我看不明白。估计类似的代码可以
在智能指针之类的实现在能看到吧。

3. protected继承
  protected继承和private继承相似。《C++编程惯用法》的作者说:我从来都没有使用过protected
继承,也没有听说有人在哪个项目中使和它。。。。如果可以使用组合,我们就应该使用组合:因为使用
语言中的晦涩特性(如保护型继承)会增大理解程序的难度。

综上所述,虽然C++中提供了大量有趣的语言特性,但我们应该用更先进的设计方法来代替这种语言特性
的过度使用。可惜C++到现在还没有引入interface,而我们常常不得不因此而使用可怕的多重继承或其他
特性,如前面所说的第4章第70页的例外情况。事实上,如果C++有interface,70页所说的那个问题就
根本不需要动用什么private继承了。

[ 本帖最后由 key 于 11-5-2009 13:11 编辑 ]
回复  

使用道具 举报

2#
发表于 11-5-2009 14:06:13 | 只看该作者

回复 #1 key 的帖子

2. private继承与组合
    在多态实现中,如果需要重载基类的虚函数,而又想对外隐藏继承关系,则用private 继承,说白了private继承是为了使用继承机制但是不引入基类的符号, 好听的说法是鱼与熊掌兼得,不好听的说法是带着牌坊做婊子

一般在这种情形下我都是这样来做:

  1. class Base
  2. {
  3. public:
  4.     virtual void DoSomeEvilThings();
  5. };

  6. class MyBeautifulObject
  7. {
  8. public:
  9.     //.......
  10. private:
  11.     MyBeautifulObjectEvilImpl  d;
  12. };

  13. class MyBeautifulObjectEvilImpl : public Base
  14. {
  15. public :
  16.      virtual void DoSomeEvilThings(); //rewrite here
  17. };
复制代码

对用户来说,这样的实现比较清晰,对实现者来说要多写一个interface类,不过这样有一个附加的好处:避免名字空间污染,避免过多的include依赖,从而加快了c++的编译速度,特别是在大量使用template的场合。
回复  

使用道具 举报

3#
 楼主| 发表于 11-5-2009 16:04:57 | 只看该作者
原帖由 coredump 于 11-5-2009 14:06 发表
2. private继承与组合
    在多态实现中,如果需要重载基类的虚函数,而又想对外隐藏继承关系,则用private 继承,说白了private继承是为了使用继承机制但是不引入基类的符号, 好听的说法是鱼与熊掌兼得,不好听的说 ...


我觉得下面这段程序可以看出C++变态的语法灵活性:
  1.   6 template<class T>
  2.   7 class X
  3.   8 {
  4.   9 public:
  5. 10     virtual ~X(){};
  6. 11     virtual void doit() { cout << "hello do" << endl; }
  7. 12
  8. 13 };
  9. 14
  10. 15 template<class T>
  11. 16 class Y : private X<T>
  12. 17 {
  13. 18 };
  14. 19
  15. 20 int main()
  16. 21 {
  17. 22     Y<int> * y = new Y<int>();
  18. 23
  19. 24     //X<int> * x = dynamic_cast<X<int> *>(y);
  20. 25     X<int> * x = static_cast<X<int> *>((void *)y);
  21. 26     x->doit();
  22. 27
  23. 28     return 0;
  24. 29 }
复制代码
只可惜这里采用了static_cast<>(),不能进行类型转换的测试。
回复  

使用道具 举报

4#
发表于 11-5-2009 16:12:13 | 只看该作者

回复 #3 key 的帖子

这不变态啊,这时候的static_cast和直接强制类型转换也没啥差别了,要说变态,还是这个变态:

(X*)(0)->doit();



PS:你为什么什么类都加上template,图增烦恼?
回复  

使用道具 举报

5#
 楼主| 发表于 11-5-2009 16:19:37 | 只看该作者
原帖由 coredump 于 11-5-2009 16:12 发表
这不变态啊,这时候的static_cast和直接强制类型转换也没啥差别了,要说变态,还是这个变态:

(X*)(0)->doit();

应该是((X *)(0))->doit()吧?
另外,这个代码会你的名字,这和我上面说的不同。

不同我同意你的说法,static_cast<>和直接强制类型转换没有啥差别,我都不知道为什么要加入
<static_cast>
<const_cast>
<reinterpret_cast>
这三个东西。可能是现在的人打字快了,多点东西输入能健脑?
  1. PS:你为什么什么类都加上template,图增烦恼? [/quote]
复制代码
强制自己使用模板。有模板声明和没有模板声明,会有一些语法上的区别,比如friend
回复  

使用道具 举报

6#
发表于 11-5-2009 16:25:06 | 只看该作者

回复 #5 key 的帖子

在上例中static_cast是和强制转换差不多,但是其他情况下是有区别的,static_cast增加了编译器的类型兼容性检查, 一些明显不兼容的转换是被禁止的。

reinterpret_cast确实是故意为之的。
回复  

使用道具 举报

您需要登录后才可以回帖 登录 | FreeOZ用户注册

本版积分规则

小黑屋|手机版|Archiver|FreeOZ论坛

GMT+10, 14-4-2025 16:05 , Processed in 0.041323 second(s), 22 queries , Gzip On, Redis On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表