======================================================
大家请把我的文章当参考,详细内容 还请参照 权威书籍
<c++ programming language>如果文中有错误和遗漏,
请指出,Aear会尽力更正, 谢谢!
Aear Blog: http://blog.sina.com.cn/u/1261532101
======================================================
今天讲的是 public inheritance, protected inheritance & private inheritance,内容不多,但是非常重要。基本的类的继承,也就是inheritance的概念大家都清楚,明确的定义不再详细说明了。先面举个例子来说明:
class People {
...
Walk();
Eat();
};
class Student : public People{
...
Study();
};
注意这行:
class Student : public People {
中的public,表明是public inheritance,如果换成protected,就是protected inheritance, private就是private inhertance. 首先需要说明的是3种inheritance在语法上相似,但是在语意上完全不同。我们先从public inheritance说起。
=====================public inheritance=====================
public inheritance最基本的概念就是"isa" ( is a )。简单的说,继承类也就是Derived Class "is a" Base Class. 用上面的例子来说,People是base class, Student是 derived class,所以能够推导出: “student is a people” 这句话。如果你无法推导出 "isa"的关系,那么就不应该使用public inheritance.
其次,即使是能推导出 "isa" 的关系,也必须满足2个条件,才能使用 public inheritance. 这2个条件是:
1. 所有Base Class的属性,也就是 attribute,Derived Class都有。
2. 所有Base Class的方法,Derived Class都应该包含。
在上面的例子中,student也是个people,所以能够Walk() 和 Eat(),因此public inheritance 是合理的。
如果满足 "isa" 但是不满足上述条件,建议使用 Delegation/Composition,具体关于Delegation和Composition,在"C++基本功和 Design Pattern系列(1)" 中有说明。让我们看下在《Effective C++》中的一个例子来说明这种情况:
class Rectangle {
...
SetWidth();
SetHeight();
};
class Square : public Rectangle {
...
SetLength();
};
我们大家都知道,一个正方形Square,一定是一个长方形Rectangle,所以满足"isa"的条件。我们给Rectangle提供了SetWidth()和SetHeight()的方法。如果不考虑上面2条,只考虑 "isa",那么这个 public inheritance是合理的,但是让我们看看会出现什么问题。
在Square中我们要求长和宽必须相等,因此我们提供了SetLength(),来同时设置正方形的长和宽。但是有一位Bill小朋友无法分辨长方形和正方形,因此写出了如下代码:
Square MySquare;
MySquare.SetWidth(100);
MySquare.SetLenght(200);
那么问题出现了,MySquare并不是一个Square。相信大家都明白了吧。语言的不精确性导致在设计过程中出现的错误是屡见不鲜的。因此,在 public inheritance的时候要特别注意。也许有人会说,我们把SetHeight 和 SetWidth设置成Virtual然后在Square Class中重载不就可以了吗?如果Rectangle和Square 2个class都是你来写,那么也许不会出现问题。但是如果一个非常复杂的class,包含几十个方法和几十个属性,并且由别人来写,那么你会不会仔细的阅读代码并且overlord每一个需要的方法呢?即使你这样做了,也许会带来更多的麻烦。因为有可能破坏内部数据的一致性。
让我们来看看interface inheritance的例子:
Class Bird {
...
virtual Fly() = 0;
};
Class Turkey : public Bird {
...
Fly() { cout << "I cannt fly! Jessus....." <<endl; };
};
Turkey Bird0;
...
Bird0.Flg(); // runtime error
首先,鸟能飞,这个没有问题,火鸡是一种鸟,这也没有问题,但是:火鸡不能飞。问题出现了,client能够调用Turkey的Fly()方法,但是得到的确是一个 RunTime Error! 这里必须强调下:"RUNTIME ERROR!",对于游戏程序来说,一个"RUNTIME ERROR"基本上就等于程序崩溃。和out of memory同等性质。如果你玩WOW做7个小时中间不能间断的任务,然后出现一只火鸡给个RUNTIME ERROR....我想是人都会崩溃吧。
所以对于这种错误,我们要在编译的时候尽量查出来,也就是 Prefer Compile Error over Runtime Error. 通过更改类的设计,我们可以避免类似的runtime error:
Class Bird {
...
};
Class UnflyableBird : public Bird{
...
// no fly() here
};
Class Turkey : public UnflyableBird {
...
};
Turkey Bird0;
...
Bird0.Flg(); // compile error....
所以,要想使用public inheritance,必须满足:
1. "ISA"
2. 所有Base Class的属性,也就是 attribute,Derived Class都有。
3. 所有Base Class的方法,Derived Class都应该包含。
=====================private inheritance=====================
private inheritance和public inheritance最大的区别就在于,private inheritance不满足"isa"的关系。举个例子:
class People {
...
Walk();
Eat();
};
class ET: private People{
...
};
外星人ET是一种类似人的生物,能做一些类似人的动作,但是并不是人。从C++的语法上面来讲,下面的代码是错误的:
People* p = new ET(); // ERROR, ET is not a People
使用private inheritance的目的只是简单的为了代码重用。因此如果不满足public inheritance的条件,可以使用 Delegation/composition 和 Private Inheritance。 那么在什么情况下使用 private inheritance,什么情况下使用Delegation/Composition 呢?
有2种情况是推荐使用 private inheritance的,其他的情况下,推荐使用Delegation/Composition.
情况1: 需要对Base Class中的 private/protect virtual 进行重载。比如类似Draw() 等等。
情况2: 不希望一个Base class被 client使用。
关于情况2,举个简单的例子:
如果我们不希望Base Class被别人直接使用,有2种方法,第一是:把它设置成为abstract class, 也就是包含pure virtual function. 第2种方法是把constructor 和 descturctor设置成 protected.代码如下:
class Base {
protected:
Base();
virtual ~Base();
};
class Derived : private Base {
...
};
Base n; // Error, Base() cannot be called
Derived m; // ok, Derived can call Base()
这样我们又可以保证n的代码可以被m使用,又可以防止 client直接调用 Base进行我们不希望的操作。
=====================protected inheritance=====================
protected inheritance和 private inheritance没有本质的区别,但是如果我们希望的 Derived Class 能够作为其他 class的基类,那么就应该使用 protected inheritance.
今天就说这么多,有空来我的Blog做客:http://blog.sina.com.cn/u/1261532101 ,下次见!