1. 动态绑定与静态多态
通过对对象的请求以及该对象的本类型定义的不同定义到不同的实现。即是程序的行为是在运行的最后时刻才被确定。
这便是面向对象系统中的多态概念,c++中有几种多态体现,包括模版化与参数多态。以及这里的动态绑定。
模版化与参数多态又被称为静态多态。模版化是c++中泛型编程的体现之一,是c++的利器,在stl中大量充斥着模版化的例子。stl中的算法一类全部都是使用模版化的技术。
2. 抽象类与具体类
抽象类把它的部分或是全部操作的实现都延迟到子类,子类能够重写(override)父类的操作,继承这个机制本身能够允许你很方便的拓展出新类,从而得到同一系列的对象族。如下图所示,AbstractClass就是一个抽象类,它的Operation操作是未被定义的抽象操作,ConcreteSubclass本身是一个具体类,它属于AbstractClass子类,重写(override)了父类的相关Operation操作。
3. 混入类(mixin class)
混入类既是c++中的多重继承的类,c++没有像java、c#一样规定单根继承,所以对于一个具体类,它可以是n个抽象类的子类。从而可以继承了n个抽象类的特性。举例来说, 蝙蝠既是哺乳动物也是能飞的生物,所以它具备了这两类生物的所有特性,这里的class Bat就是混入类。
class Mammal
{
public:
virtual void Breathe();
};
class FlyCreature
{
public:
virtual void Fly();
};
class Bat :public Mammal, public FlyCreature
{
public:
void Breathe()
{
//Breathe with lung
}
void Fly()
{
// fly with wing
}
};
4. 类继承与接口继承
c++里没有明确区分类继承与接口继承,一般来说继承有一个纯虚函数的抽象类就是接口继承,其他则为类继承。
java与c#有明确的界定,所有的继承都是类继承,所有implement关键字限定的继承就是接口继承。
5. 继承与组合
这两个概念都是为了一个目的,复用已有代码。继承对于子类来说父类的实现都是可见的,所以这种方式又被称为白箱复用。举例来说,通过类Bat生成的对象可以直接使用FlyCreature的成员函数,但是父类FlyCreature对于子类Bat来说是可被重写(override)的,所以Bat对FlyCreature 的复用就是属于白箱复用。
class Mammal
{
public:
virtual void Breathe();
};
class FlyCreature
{
public:
void Fly()
{
//fly With Wing
}
};
class Bat :public Mammal, public FlyCreature
{
public:
void Breathe()
{
//Brea with lung
}
};
而对于组合来说,工具类的使用只能通过该类暴露出来的成员函数,所以这类复用又被称为黑箱复用。举例来说Bat通过对象obj实现了Fly的动作,FlyCreature类对Bat来说是不可重写(override)的,所以Bat对FlyCreature的复用就属于黑箱复用。
class Mammal
{
virtual void Breathe();
};
class FlyCreature
{
void Fly()
{
//fly with wing
}
};
class Bat :public Mammal
{
void Breathe()
{
//Breathe with lung
}
void FlyWithWing()
{
FlyCreature obj;
obj.FlyWithWing();
}
};
6. 委托与c++的impl惯用法
委托实际上是组合的一种体现形式,在c++中通过传递一个工具类的指针来使用工具类的功能。这种代码复用方式被称为委托。
impl惯用法可用来实现委托,它是c++的常用技巧之一。在c++中,对于一个客户类来说它需要的只是一个工具类的指针与申明,对于实现的详细信息它并不用关注。所以我们经常可以使用一个对象指针或引用来代替一个对象,在另外的cpp中实现该对象的类。这样从物理分布上隔离了实现与抽象,既达到了对客户隐藏实现的目的,又可以受益于动态绑定或是类型检测给程序带来的好处。同时对于一个指针或是引用来说拷贝它本身代价是及其小的,在一些效率要求较高的程序来说,传递此类变量的受益是及其大的。