C++的三种继承类型问题
继承是面向对象的主要特征之一(另一是封装),我们的直觉概念中,继承实现了一种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 编辑 ]
回复 #1 key 的帖子
2. private继承与组合在多态实现中,如果需要重载基类的虚函数,而又想对外隐藏继承关系,则用private 继承,说白了private继承是为了使用继承机制但是不引入基类的符号, 好听的说法是鱼与熊掌兼得,不好听的说法是带着牌坊做婊子;P
一般在这种情形下我都是这样来做:
class Base
{
public:
virtual void DoSomeEvilThings();
};
class MyBeautifulObject
{
public:
//.......
private:
MyBeautifulObjectEvilImpld;
};
class MyBeautifulObjectEvilImpl : public Base
{
public :
virtual void DoSomeEvilThings(); //rewrite here
};
对用户来说,这样的实现比较清晰,对实现者来说要多写一个interface类,不过这样有一个附加的好处:避免名字空间污染,避免过多的include依赖,从而加快了c++的编译速度,特别是在大量使用template的场合。 原帖由 coredump 于 11-5-2009 14:06 发表 http://www.freeoz.org/forum/images/common/back.gif
2. private继承与组合
在多态实现中,如果需要重载基类的虚函数,而又想对外隐藏继承关系,则用private 继承,说白了private继承是为了使用继承机制但是不引入基类的符号, 好听的说法是鱼与熊掌兼得,不好听的说 ...
我觉得下面这段程序可以看出C++变态的语法灵活性:6 template<class T>
7 class X
8 {
9 public:
10 virtual ~X(){};
11 virtual void doit() { cout << "hello do" << endl; }
12
13 };
14
15 template<class T>
16 class Y : private X<T>
17 {
18 };
19
20 int main()
21 {
22 Y<int> * y = new Y<int>();
23
24 //X<int> * x = dynamic_cast<X<int> *>(y);
25 X<int> * x = static_cast<X<int> *>((void *)y);
26 x->doit();
27
28 return 0;
29 }只可惜这里采用了static_cast<>(),不能进行类型转换的测试。
回复 #3 key 的帖子
这不变态啊,这时候的static_cast和直接强制类型转换也没啥差别了,要说变态,还是这个变态:(X*)(0)->doit();
;P
PS:你为什么什么类都加上template,图增烦恼? 原帖由 coredump 于 11-5-2009 16:12 发表 http://www.freeoz.org/forum/images/common/back.gif
这不变态啊,这时候的static_cast和直接强制类型转换也没啥差别了,要说变态,还是这个变态:
(X*)(0)->doit();
应该是((X *)(0))->doit()吧?
另外,这个代码会你的名字,这和我上面说的不同。
不同我同意你的说法,static_cast<>和直接强制类型转换没有啥差别,我都不知道为什么要加入
<static_cast>
<const_cast>
<reinterpret_cast>
这三个东西。可能是现在的人打字快了,多点东西输入能健脑?PS:你为什么什么类都加上template,图增烦恼? 强制自己使用模板。有模板声明和没有模板声明,会有一些语法上的区别,比如friend
回复 #5 key 的帖子
在上例中static_cast是和强制转换差不多,但是其他情况下是有区别的,static_cast增加了编译器的类型兼容性检查, 一些明显不兼容的转换是被禁止的。reinterpret_cast确实是故意为之的。
页:
[1]