第7章 Polymorphism 多态
7.1 类型转换 Conversions
(1)public继承,应该包含替换:即将子类转成父类(子类是父类的超集)
(a)如果B是A的子类,那么能使用A的地方,一定能使用B
(b)如果B是A的子类,那么对A成立的,对B也成立
class A{ int m_a; public: int getA(){m_a = 0; return m_a;} } class B : public A{ int getA(){m_a = 10; return m_a;} } void func(A a){ cout << getA(); } int main(){ B b_ins; func(b_ins); }
|

7.1.1 向上转换 Upcast
Manager pete("Pete", "444-55-6666", "Bakey"); Employee* ep = &pete; Employee& er = pete;
ep->print( cout );
|
例:drawing
1 具体对象、共有数据、接口

2 继承结构


在父类Shape中,定义了接口render()
在子类中,通过多态的机制,重定义接口render()
3 类的声明
class XYPos{ ... }; class Shape { protected: XYPos center;
public: Shape(); virtual ~Shape(); virtual void render(); void move(const XYPos&); virtual void resize();
};
|
7.2 多态 Polymorphism
向上转换upcast:将子类的对象作为父类的一个对象
多态使用的时间:upcast
多态的目的:在upcast的时候,使用子类的对象
动态绑定binding:
绑定binding:调用哪个函数
静态绑定static
binding:调用函数作为代码
动态绑定dynamic binding:调用对象的函数
7.2.1 non-virtual function
(1)视为静态绑定,编译时就确定好使用哪个函数
(2)调用较快
7.2.2 virtual function
- 子类一定要重定义该函数
- 对象存储了虚函数的信息
- 编译器会检查、并动态调用正确的函数
- 编译器优化:如果编译器在编译的时候知道应该调用哪个函数,则会生成一个静态调用
class Ellipse : public Shape { protected: float major_axis, minor_axis; public: Ellipse(float maj, float minr); virtual void render(); };
class Circle : public Ellipse { public: Circle(float radius):Ellipse(radius, radius){} virtual void render(); };
void render(Shape* p) { p->render(); }
void func() { Ellipse ell(10, 20); ell.render();
Circle circ(40); circ.render();
render(&ell); render(&circ); }
|
7.3 抽象基础类 Abstract base
classes
7.3.1 定义
- 一个抽象的基础类有纯虚函数pure virtual
functions
- 只定义返回值、参数
- 不需要给函数体
- 抽象基础类不能直接实例化≠不能用指针
必须由一个子类继承
子类必须要实现抽象类的所有纯虚函数
7.3.2 例:定义纯虚函数
class XYPos{ ... }; class Shape { protected: XYPos center; public: Shape(); virtual void render() = 0; void move(const XYPos&); virtual void resize(); };
|
7.3.3 作用
(1)便于建模 ==> 抽象定义
(2)强制要求正确的行为 ==> 所有子类都必须有该行为
(3)定义接口,而不是定义实现
7.3.4 例:定义抽象类
class CDevice { public: virtual ~CDevice();
virtual int read(...) = 0; virtual int write(...) = 0; virtual int open(...) = 0; virtual int close(...) = 0; virtual int ioctl(...) = 0; };
|
(1)所有非静态的成员函数都是纯虚函数,除了析构函数
(2)虚拟析构函数,没有函数体
(3)没有非静态的成员变量,可以有静态成员变量
7.4 Virtual的实现机制
(1)在内存中,会存储一个指针,指向当前类的虚函数表
(2)一个class会有一个虚函数表
(3)父类的变量会在子类的变量之前
(4)子类的虚函数表中,不会有父类的虚函数表,因为子类已经将所有虚函数重新定义了




7.5 赋值与upcast
Ellipse elly(20f,40f); Circle circ(60f); elly = circ; elly.render();
Ellipse *elly = new Ellipse(20f,40f); Circle *circ = new Circle(60f); elly = circ; elly->render();
|
7.6 Relaxation
虚函数的返回类型为指针、引用的时候,子类可以修改返回类型
虚函数的返回类型为class的时候,子类不能修改返回类型
class Expr{ public: virtual Expr* newExpr(); virtual Expr& clone(); virtual Expr self(); } class BinaryExpr: public Expr{ public: virtual BinaryExpr* newExpr(); virtual BinaryExpr& clone(); }
|
7.7 Overloading and virtuals
重载的几个函数,都需要被子类重定义
class Bass{ public: virtual void func(); virtual void func(int); } class Derived: public Base{ public: virtual void func(){ Base::func(); } virtual void func(int){...}; }
|
7.8 注意
(1)不要重新定义non-virtual的函数
(2)不要重定义继承函数的缺省值
class A { public: A() { f();} virtual void f() { cout << "A::f()"; } }; class B : public A { public: B() { f();} void f() { cout << "B::f()"; } };
|