引言
多态,Polymorphsim,多种状态,面向对象程序设计的核心。
据说,这是OOP程序员在应聘的时候,第一大考点!!!!!!
就我目前的认知水平来看,多态的出现,是为了在庞大的软件工程里,降低开发的复杂度。
e.g. 一个软件工程量很大,通过定义一些接口,interface,不同的人按照这些接口所指定的规则(输入、输出),
去实现具体的内容。最后,软件统一整合的时候,才能对接得上,相当于是协作关系。
不过我觉得吧,定义一堆函数,不也就可以吗?找xxx去实现函数a,找yyy去实现函数b。这样看起来,似乎也可以啊……
难道这成了面向过程的了?难道这样不能大家一起合作开发吗?
暂时还是没有太能理解这种设计思想……哎…………【注意】后面一个案例,就可以体现。没有多态,开发起来很麻烦!
按照百度百科的说法,在OOP中,接口的不同实现方式,就叫做多态。
如果某种程序设计语言,有对象,但是不支持多态,那么只能叫基于对象(object based),不能叫面向对象(object oriented)。
现在也没太能理解这种意思。
反正我现在的理解就是,运用多态,似乎可以更好地让一群人分工合作,协同开发。类似于自己制定的一套规范,标准。还有,解耦合?没懂……
就像当时看一些JAVA框架的时候,e.g. struts,就相当于制定了一套规范。e.g. MVC,每一个view(jsp)的下一步一定是调到一个controller(java)去…
这样,好像就是行业标准吧。行业标准似乎就是为了实现大统一,只要我们都符合这个标准,只要都按照这种规范去开发,你能用我的,我也能用你的。
就像用USB线给手机充电一样。普通USB数据线,不管是三星,还是小米,还是华为,只要这些手机的充电口都统一符合“采用某种USB接口研发、生产制造”的标准,那这些手机的充电线是可以通用的。至于手机里面怎么充电的,是什么电池,容量多少,好像并不关心。手机充电头那边是怎么把220V转成5V,1A的输出,也无所谓。只在乎“你有android手机的充电线吗?”这句话。
再举一个“多态”的例子。
我听别人说的。
一位老板,一声令下,“走吧!”
司机,开左前车门,从左前车门上车,发动汽车。
保镖,开右后车门,请老板上车。待老板上车后,自己开右前车门,上车。
老板,从右后车门,上车。
秘书,开左后车门,从左后车门上车。
尽管,同一个“函数”也好、“命令”也好,但是,不同的角色,不同的人,却有不同的动作和响应。这就是多态。
而不是需要老板说,司机,你干嘛干嘛,保镖,你干嘛干嘛,小秘,你又干嘛干嘛。这样累不累?
【经典案例】
清华的某位教授说,什么叫经典例题?
1. 本来就很经典;
2. 每次做,都会有新的收获!
#include <iostream>
#include <string>
using namespace std;
class CAnimal
{
public:
CAnimal();
virtual ~CAnimal();
virtual void showName() const{
cout<<"动物:我不知道我是谁"<<endl;
}
virtual void say() const{
cout<<"动物:我不知道怎么叫"<<endl;
}
virtual void eat() const{
cout<<"动物:我不知道吃什么"<<endl;
}
protected:
string name;
private:
};
CAnimal::CAnimal()
{
}
CAnimal::~CAnimal()
{
}
class CCat : public CAnimal
{
public:
CCat();
~CCat();
void showName() const{
cout<<"动物:我是猫"<<endl;
}
void say() const{
cout<<"动物:喵喵喵"<<endl;
}
void eat() const{
cout<<"动物:我吃鱼"<<endl;
}
private:
};
CCat::CCat()
{
}
CCat::~CCat()
{
}
class CDog : public CAnimal
{
public:
CDog();
~CDog();
void showName() const{
cout<<"动物:我是狗"<<endl;
}
void say() const{
cout<<"动物:汪汪汪"<<endl;
}
void eat() const{
cout<<"动物:我啃骨头"<<endl;
}
private:
};
CDog::CDog()
{
}
CDog::~CDog()
{
}
class CFood
{
public:
CFood();
virtual ~CFood();
virtual void showName() const{
cout<<"食物:我不知道我是什么食物"<<endl;
}
private:
};
CFood::CFood()
{
}
CFood::~CFood()
{
}
class CFish : public CFood
{
public:
CFish();
~CFish();
void showName() const{
cout<<"食物:我是鱼"<<endl;
}
private:
};
CFish::CFish()
{
}
CFish::~CFish()
{
}
class CBone : public CFood
{
public:
CBone();
~CBone();
void showName() const{
cout<<"食物:我是骨头"<<endl;
}
private:
};
CBone::CBone()
{
}
CBone::~CBone()
{
}
class CMaster
{
public:
CMaster();
~CMaster();
void feed(CAnimal & an, CFood & food) const{
an.showName();
an.say();
food.showName();
an.eat();
}
private:
};
CMaster::CMaster()
{
}
CMaster::~CMaster()
{
}
int main () {
CAnimal * an = new CCat;
CFood * food = new CFish;
CMaster * master = new CMaster;
master->feed(*an,*food);
delete an;
delete food;
delete master;
system("pause");
return 0;
}
动物:我是猫
动物:喵喵喵
食物:我是鱼
动物:我吃鱼
主人类中,feed函数,本来按理说就应该填一个动物,填一种食物,就好。
多态提供了足够的灵活性!
主人类中,代码可以写得很少啊!!!(有助于开发,特别是有助于减少架构师的工作量…)
如果没有多态,主人类中,要重载至少2个函数嘛。
一个给猫喂鱼,一个给狗喂骨头。
要是有更多的子类,主人类的开发要被写死!而且,维护起来很困难啊!
多态概述
– function overloading and operator overloading at compile time(编译时多态)
– function overriding at run-time associate many meanings to one function (运行时多态)
– enable programmers to design a common interface that can be used on different but related objects
– reduce complexity and development time
– apply static binding
– advantage of fast speed
– realized by function overloading and operator overloading
– apply dynamic binding
– advantage of enhanced flexibility
– realized by inheritance + virtual functions
In C++, redefining a virtual function in a derived class is called overriding a function.
绑定的方式
– can assign a derived-class object to a base-class object // 1. 在assign的时候,可以向上转型!
– can copy the address of a derived-class object to a pointer of a base-class object // 2. 可以把派生类的地址assign给指向基类的指针
– a derived-class object can be a reference to base-class object // 3. 可以写 B0 & b0 = D1;
But! can only access members in the base class, not members in the derived class ( 都只能范围基类中的成员!不能访问派生类中的成员!)
虚函数
– don’t know how function is implemented
– wait until used in program
– get implementation from object instance
– call dynamic (late) binding
#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;
class B0 {
public:
void ShowFun() { //not virtual
cout << "B0::ShowFun()" << endl; }
};
class C0 : public B0 {
public:
virtual void ShowFun() { //virtual
cout << "C0::ShowFun()" << endl; }
};
class C1 : public C0 {
public:
void ShowFun() { //virtual
cout << "C1::ShowFun()" << endl; }
};
class C2 : public C1 {
public:
void ShowFun() { //virtual
cout << "C2::ShowFun()" << endl; }
};
void FunPtr(C0 *ptr) {
ptr->ShowFun();
}
int main()
{
B0 w, *p; C0 x, *q;
C1 y; C2 z;
p = &w; p->ShowFun();
p = &y; p->ShowFun(); //Q1: what happen??
q = &x; FunPtr(q); //Q2: which to call?
q = &y; FunPtr(q);
q = &z; FunPtr(q);
//q = &w; FunPtr(q); //Q3: what happen??
//FunPtr(&w); //Q4: what happen?? => cannot covert from B0* to C0*; but the reverse can
//FunPtr(p); //Q5: what happen?? => cannot covert from B0 to C0* ; but the reverse can
system("pause");
return 0;
}
结果。
C0::ShowFun() // 虚函数。 showFun在B0里已经是虚函数了。在子类中也会是虚函数!尽管override了!
C1::ShowFun() //
C2::ShowFun()
class A { public:
~A() { cout << “A::~A()\n”;}
};
class C : public A {
int * iary;
public:
C(int i) { iary = new int [i]; }
~C() {
delete [] iary;
cout << “C::~C()\n”; }
};
//in main()
A *pa = new C(10);
delete pa;
派生类对象开辟的内存,并没有回收!!!
所以,一定要把析构函数写成虚函数!!!
#include <iostream>
using namespace std;
class CB0
{
public:
CB0() {};
~CB0() {};
void fun() {
cout<<"CB0::fun()"<<endl;
}
void fun(int i) {
cout<<"CB0::fun(int i) "<<endl;
}
};
class CD0 : public CB0
{
public:
CD0() {};
~CD0() {};
void fun(int i) {
cout<<"CD0::fun(int i) "<<endl;
}
};
int main () {
CB0 * obj1 = new CD0; // 父类声明,却有两个fun
obj1->fun();
obj1->fun(0);
CD0 obj2;
obj2.fun(0); // 子类声明,只有这一个了!
system("pause");
return 0;
}
CB0::fun(int i)
CD0::fun(int i)
#include <iostream>
using namespace std;
class CB0
{
public:
CB0() {};
virtual ~CB0() {};
virtual void fun() {
cout<<"CB0::fun()"<<endl;
}
virtual void fun(int i) {
cout<<"CB0::fun(int i) "<<endl;
}
private:
};
class CD0 : public CB0
{
public:
CD0() {};
~CD0() {};
virtual void fun(int i) {
cout<<"CD0::fun(int i) "<<endl;
}
private:
};
int main () {
CB0 * obj1 = new CD0; // 父类声明,却有两个fun
obj1->fun();
obj1->fun(0);
CD0 d0;
d0.fun(1); // 子类声明,只有一个fun。在子类中,override过什么,同名的就只有什么了。
system("pause");
return 0;
}
CD0::fun(int i) // 由于多态,调用子类的fun。一定要是整个函数一模一样,才算覆写!覆写≠重载!
CD0::fun(int i) // 本来就是用CD0声明的,所以肯定调用子类的。
class B { public:
void f() { cout << “Bf ”; }
virtual void g(){ cout << “Bg ”; }
void h() { g(); f(); }
virtual void m(){ g(); f(); }
};
class D : public B { public:
void f() { cout << “Df ”; }
void g() { cout << “Dg ”; }
void h() { f(); g(); }
void m(int i) {f(); g();}
};
//in main()
D d; B *pB = &d;
pB->f(); pB->g(); pB->h(); pB->m();
结果会是:
纯虚函数
– can only be used as base class
– no objects can ever be created from it
because it doesn’t include complete definitions of all its members
– also an abstract base class
virtual void Area()=0; //pure virtual!