本文部分内容节选自Effective C++ by Scott Meyers 和 UML面向对象设计基础 by Meilir Page-Jones。
3 多态
3.1 概述
简单来说,多态(polymorphism)是具有表现多种形态的能力的特征,这使得开发语言具有根据对象的类型以不同方式进行处理的能力。多态意味着许多类可以提供同样的属性或者方法,而且调用者在调用这些属性或方法之前,不必知道某个对象是什么类型。
3.2 虚拟函数
在了解了继承的概念之后, 如果再深入一些,你会发现它分为两类,函数接口(function interface)的继承和函数实现(function implementations)的继承。虚拟函数(virtual function)意味着“接口必须被继承下去”;纯虚拟函数(pure virtual function)则意味着“只有接口必须被继承下去”;而“非虚拟函数”则意味着“接口和实现都必须被继承下去”。
对于一般(非纯)虚拟函数和纯虚拟函数,子类都会继承函数的接口,但不同的是,一般的虚拟函数传统上都会提供一份实现代码,子类可以选择是否加以改写(override)。所以一般(非纯)虚拟函数的目的,是为了让子类继承该函数的接口和缺省行为。但是,允许一般虚拟函数同时指定“函数声明”和“缺省行为”,有时可能会造成危险,考虑一下XYZ航空公司所设计的继承体系,该公司只有两种飞机,A型和B型,两者都以相同的方式飞行,因此继承体系这样设计:
class Airpost{…}; // 机场
class Airplane
{
public:
virtual void fly(const Airpost& destination);
…
}
void Airplane::fly(const Airport& destination)
{
default code for flying
}
class ModelA : public Airplane{…};
class ModelB : public Airplane{…};
为了表示所有飞机都必须能飞,并考虑到“不同型号的飞机原则上需要不同的fly实现代码”,Airplane::fly被声明为virtual。然而为了避免在ModelA和ModelB中撰写相同的代码,缺省的飞行行为由Airplane::fly提供,用时被ModelA和ModelB继承。这个设计突出共同性质,避免代码重复,并提供在未来进行强化的能力,延缓长期维护所需付出--这些都是正式面向对象技术如此收到欢迎的原因。假设XYZ公司利润大增,决定购买一种新的C型飞机。C型飞机和A型以及B型都不相同,更准确的说,它的飞行方式不同。XYZ的开发人员在继承体系中为C型飞机增加了一个class,但由于他们急着让新飞机上线服务,竟忘记重新定义(define)其fly函数。这会造成灾难:因为这个软件试图以ModelA或者ModelB的飞行方式来飞ModelC。
问题并不在于Airplane::fly提供的缺省行为,而是在于ModelC在未明白说“我要使用缺省行为“的情况下继承了该缺省行为,以下是一种解决方法:
class Airplane
{
public:
virtual void fly(const Airpost& destination) = 0;
…
protected:
void defaultFly(const Airport& destnation);
}
class ModelA : public Airplane
{
public:
virtual void fly(const Airport& destination)
{defaultFly(destination);} // inline 调用
…
};
class ModelB : public Airplane
{
public:
virtual void fly(const Airport& destination)
{defaultFly(destination);} // inline 调用
…
};
class ModelC : public Airplane
{
public:
virtual void fly(const Airport& destination)
…
};
void ModelC::fly(const Airport& destination)
{
code for flying ModelC
}
虽然开发人员还是可能因为剪贴代码来实现ModelC而招致麻烦,但是它的确比原先的设计值得信赖。Airplane::defaultFly不是一个虚拟函数,这一点很重要。因为没有任何一个子类应该重新定义此函数。
也有人反对这种以不同的函数分别提供接口和缺省行为,就像上述的fly和defaultFly那样,因为这样会造成class内部命名空间(naming space)的污染。但是他们也同意,接口和缺省行为应该分开,那么这个表面上看起来的矛盾该如何解决?在C++中,可以为纯虚拟函数提供定义(defination),不过调用它的惟一途径是所谓的静态调用,例如:
class Shape
{
public:
virtual void draw() const = 0;
virtual void error(const string& msg);
int objectId() const;
}
class Rectangle : public Shape {…};
class Ellipse : public Shape {…};
Shape *ps = new Rectange;
ps1->Shape::draw();
回到XYZ公司,以下这个新的设计几乎和之前的一样,但是纯虚拟函数Airplane::fly的实现取代了成员函数Airplane::defaultFly。这利用了“纯虚拟函数必须在子类中重新声明(declare),但是纯虚拟函数也可以拥有自己的定义(defination)”这个事实。但是这种设计也有个问题是,丧失了让Airplane::fly的声明和定义有不同的保护级别的机会。
class Airplane
{
public:
virtual void fly(const Airpost& destination) = 0;
…
}
void Airplane::fly(const Airport& destination)
{
//default code for flying
}
class ModelA : public Airplane
{
public:
virtual void fly(const Airport& destination)
{Airplane::fly(destination);}
…
};
class ModelB : public Airplane
{
public:
virtual void fly(const Airport& destination)
{ Airplane:: (destination);}
…
};
class ModelC : public Airplane
{
public:
virtual void fly(const Airport& destination)
…
};
void ModelC::fly(const Airport& destination)
{
//code for flying ModelC
}
有了以上知识,当你声明你的成员函数(member function)的时候,就必须谨慎选择,不要把所有的成员函数都声明非虚拟函数,这使得子类没有足够的空间进行特殊化工作。非虚拟的析构函数(destructors)尤其会带来问题。同时也不要把所有的成员函数都声明成虚拟函数(请思考Java是怎么做的?),因为对于一个继承体系而言,有些行为是不会变化的,如果你想确保“不变性”,那么就使用非虚拟函数。
分享到:
相关推荐
Python 3 Object Oriented Programming 英文无水印pdf pdf所有页面使用FoxitReader和PDF-XChangeViewer测试都可以打开 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请...
Python 3 Object-Oriented Programming(2nd) 英文无水印pdf 第2版 pdf所有页面使用FoxitReader和PDF-XChangeViewer测试都可以打开 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如...
Object Oriented Programming-An Evolutionary Approach
随着版本的不断更新与功能增强,从MATLAB 7版本开始,引入了面向对象编程(Object-Oriented Programming, OOP)的概念,这为用户提供了更为强大的编程工具。 面向对象编程是一种编程范式,其核心思想是将程序中的数据...
首先,关于书籍标题“Object-oriented programming with C”,它涉及到的是使用C语言进行面向对象编程的概念。尽管C语言本身不直接支持类和继承这样的面向对象特性,但它能够通过特定的设计模式来模拟这些特性。这本...
Object Oriented Programming in Common Lisp, A Programmer's Guide to CLOS
《Object-Oriented Programming with Object C》是一本深入探讨面向对象编程(OOP)与Objective-C语言的专业书籍。Objective-C是Apple开发的一种强大的、面向对象的编程语言,主要用于iOS和macOS的应用程序开发。这...
**第3章:循环与决策** 这一章重点讲解循环结构(如for、while)和条件语句(如if-else)。通过这些控制结构,程序员可以实现逻辑判断和重复执行代码块的功能,这是构建复杂程序不可或缺的一部分。 #### 第二部分...
Swift 3 Object Oriented Programming(2nd) 英文无水印pdf 第2版 pdf所有页面使用FoxitReader和PDF-XChangeViewer测试都可以打开 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有...
《C语言中的面向对象编程》一文由Laurent Deniau撰写,首次发布于2001年3月10日,并在同年5月17日进行了修订。本文旨在为基于ISO C89标准的大型项目提供面向对象设计的好处,通过一系列编程技巧使C语言能够实现面向...
Swift 3 Object Oriented Programming - Second Edition by Gastón C. Hillar English | 6 Mar. 2017 | ISBN: 1787120392 | 254 Pages | EPUB/PDF (conv) | 32.1 MB Key Features Leverage the most efficient ...
Learn popular Object-Oriented programming (OOP) principles and design patterns to build robust apps Implement Object-Oriented concepts in a wide range of frontend architectures Capture objects from ...
Beginning with an explanation of the procedure-oriented programming system, the role played by structures in this system, and the reasons that led to the creation of OOPS, the book provides a ...
Object – Oriented Programming C++ Simplified 英文无水印pdf pdf所有页面使用FoxitReader和PDF-XChangeViewer测试都可以打开 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有...
Object-Oriented Programming in C++Object-Oriented Programming in C++Object-Oriented Programming in C++