根源为总结http://www.cnblogs.com/clongge/archive/2008/07/09/1239076.html
面向对象的编程语言不止仅仅多了个类,类可以明显感觉到抽象和封装。抽象的是具体的实现,封装的是接口。
继承,分为实现继承,接口继承,可视化继承。
实现继承就是重新写一个函数去实现。这儿用的是纯虚函数。父辈纯虚,子辈必须重新实现。
接口继承是指纯粹继承父辈的老底,也可以去重新实现。这是虚函数。
可视化继承则是纯粹的全部自己实现,自己功能自己解决。对应的是非虚函数。
继承的时候父子有几种关系,比如B继承A,一种是泛化,换句话就是b是a的一种,比如老师一种人,学生是一种人。杀人犯也是一种人。这叫泛化。这儿可以接口继承或者可视化继承。因为本质是一种的关系么。这儿可以直接用父辈的老底。
在一中是聚合,聚合呢就是b是a的一部分,但是b不是一种a,比如头有眼睛鼻子嘴巴耳朵,这样就要独自去实现。这儿用到的是接口继承和纯虚类。毕竟不能说眼睛是头的一种么,要自己去实现很多的东西。
以上继承的本质是为了更方便的代码复用,而多态则是接口复用。接口复用可以用重载函数来做,也可以用类的多态性来进行。
多态,则更多的是可以用子辈赋给父辈的引用或者指针,然后可以在运行的时候去实现访问子类。这样就看似是一个,还有待补充。慢慢来。看图很不错的。
多态代码
//小结:1、有virtual才可能发生多态现象
// 2、不发生多态(无virtual)调用就按原类型调用
#include<iostream>
using namespace std;
class Base
{
public:
virtual void f(float x)
{
cout<<"Base::f(float)"<< x <<endl;
}
void g(float x)
{
cout<<"Base::g(float)"<< x <<endl;
}
void h(float x)
{
cout<<"Base::h(float)"<< x <<endl;
}
};
class Derived : public Base
{
public:
virtual void f(float x)
{
cout<<"Derived::f(float)"<< x <<endl; //多态、覆盖
}
void g(int x)
{
cout<<"Derived::g(int)"<< x <<endl; //隐藏
}
void h(float x)
{
cout<<"Derived::h(float)"<< x <<endl; //隐藏
}
};
int main(void)
{
Derived d;
Base *pb = &d;
Derived *pd = &d;
// Good : behavior depends solely on type of the object
pb->f(3.14f); // Derived::f(float) 3.14
pd->f(3.14f); // Derived::f(float) 3.14
// Bad : behavior depends on type of the pointer
pb->g(3.14f); // Base::g(float) 3.14
pd->g(3.14f); // Derived::g(int) 3
// Bad : behavior depends on type of the pointer
pb->h(3.14f); // Base::h(float) 3.14
pd->h(3.14f); // Derived::h(float) 3.14
return 0;
}
令人迷惑的隐藏规则
本来仅仅区别重载与覆盖并不算困难,但是C++的隐藏规则使问题复杂性陡然增加。
这里“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual
关键字,基类的函数将被隐藏(注意别与重载混淆)。
(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual
关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。
上面的程序中:
(1)函数Derived::f(float)覆盖了Base::f(float)。
(2)函数Derived::g(int)隐藏了Base::g(float),而不是重载。
(3)函数Derived::h(float)隐藏了Base::h(float),而不是覆盖。