多态的表现形式是什么 java中多态的四种形式是什么

www.zhiqu.org     时间: 2024-05-28

多态指同一个实体同时具有多种形式。它是面向对象程序设计(OOP)的一个重要特征。如果一个语言只支持类而不支持多态,只能说明它是基于对象的,而不是面向对象的。C++中的多态性具体体现在运行和编译两个方面。

运行时多态是动态多态,其具体引用的对象在运行时才能确定。编译时多态是静态多态,在编译时就可以确定对象使用的形式。

多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。

C++中,实现多态有以下方法:虚函数,抽象类,覆盖,模板(重载和多态无关)。

OC中的多态:不同对象对同一消息的不同响应.子类可以重写父类的方法

多态就是允许方法重名 参数或返回值可以是父类型传入或返回。

多态也指生物学中腔肠动物的特殊的生活方式。水螅态与水母态的世代交替现象。

扩展资料:

多态作用:

把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。

赋值之后,父类型的引用就可以根据当前赋值给它的子对象的特性以不同的方式运作。也就是说,父亲的行为像儿子,而不是儿子的行为像父亲。

举个例子:从一个基类中派生,响应一个虚命令,产生不同的结果。

比如从某个基类派生出多个子类,其基类有一个虚方法Tdoit,然后其子类也有这个方法,但行为不同,然后这些子类对象中的任何一个可以赋给其基类对象的引用。

或者说将子对象地址赋给基类指针,这样其基类的对象就可以执行不同的操作了。实际上你是在通过其基类的引用来访问其子类对象的,你要做的就是一个赋值操作。

使用继承性的结果就是当创建了一个类的家族,在认识这个类的家族时,就是把子类的对象当作基类的对象,这种认识又叫作upcasting(向上转型)。

这样认识的重要性在于:我们可以只针对基类写出一段程序,但它可以适应于这个类的家族,因为编译器会自动找出合适的对象来执行操作。这种现象又称为多态性。而实现多态性的手段又叫称动态绑定(dynamic binding)。

参考资料来源:百度百科-多态



一种是父类与子类之间表现 重写
还有一种是重载 在同一个类中,同样的方法,有不同的实现方式
这两种也是多态的表现

父类引用指向子类对象。

多态的定义是什么?代码的表现形式是?~

状态。继承中的多种状态等等。。。





C++多态技术
摘要

本文描述了C++中的各种多态性。重点阐述了面向对象的动态多态和基于模板的静态多态,并初步探讨了两种技术的结合使用。

关键词

多态 继承 虚函数 模板 宏 函数重载 泛型编程 泛型模式

导言

多态(polymorphism)一词最初来源于希腊语polumorphos,含义是具有多种形式或形态的情形。在程序设计领域,一个广泛认可的定义是“一种将不同的特殊行为和单个泛化记号相关联的能力”。和纯粹的面向对象程序设计语言不同,C++中的多态有着更广泛的含义。除了常见的通过类继承和虚函数机制生效于运行期的动态多态(dynamic polymorphism)外,模板也允许将不同的特殊行为和单个泛化记号相关联,由于这种关联处理于编译期而非运行期,因此被称为静态多态(static polymorphism)。
事实上,带变量的宏和函数重载机制也允许将不同的特殊行为和单个泛化记号相关联。然而,习惯上我们并不将它们展现出来的行为称为多态(或静态多态)。今天,当我们谈及多态时,如果没有明确所指,默认就是动态多态,而静态多态则是指基于模板的多态。不过,在这篇以C++各种多态技术为主题的文章中,我们首先还是回顾一下C++社群争论已久的另一种“多态”:函数多态(function polymorphism),以及更不常提的“宏多态(macro polymorphism)”。

函数多态

也就是我们常说的函数重载(function overloading)。基于不同的参数列表,同一个函数名字可以指向不同的函数定义:

// overload_poly.cpp

#include <iostream>
#include <string>

// 定义两个重载函数

int my_add(int a, int b)
{
return a + b;
}

int my_add(int a, std::string b)
{
return a + atoi(b.c_str());
}

int main()
{
int i = my_add(1, 2); // 两个整数相加
int s = my_add(1, "2"); // 一个整数和一个字符串相加
std::cout << "i = " << i << "
";
std::cout << "s = " << s << "
";
}

根据参数列表的不同(类型、个数或兼而有之),my_add(1, 2)和my_add(1, "2")被分别编译为对my_add(int, int)和my_add(int, std::string)的调用。实现原理在于编译器根据不同的参数列表对同名函数进行名字重整,而后这些同名函数就变成了彼此不同的函数。比方说,也许某个编译器会将my_add()函数名字分别重整为my_add_int_int()和my_add_int_str()。

宏多态

带变量的宏可以实现一种初级形式的静态多态:
// macro_poly.cpp

#include <iostream>
#include <string>

// 定义泛化记号:宏ADD
#define ADD(A, B) (A) + (B);

int main()
{
int i1(1), i2(2);
std::string s1("Hello, "), s2("world!");
int i = ADD(i1, i2); // 两个整数相加
std::string s = ADD(s1, s2); // 两个字符串“相加”
std::cout << "i = " << i << "
";
std::cout << "s = " << s << "
";
}
当程序被编译时,表达式ADD(i1, i2)和ADD(s1, s2)分别被替换为两个整数相加和两个字符串相加的具体表达式。整数相加体现为求和,而字符串相加则体现为连接。程序的输出结果符合直觉:
1 + 2 = 3
Hello, + world! = Hello, world!

动态多态

这就是众所周知的的多态。现代面向对象语言对这个概念的定义是一致的。其技术基础在于继承机制和虚函数。例如,我们可以定义一个抽象基类Vehicle和两个派生于Vehicle的具体类Car和Airplane:

// dynamic_poly.h

#include <iostream>

// 公共抽象基类Vehicle
class Vehicle
{
public:
virtual void run() const = 0;
};

// 派生于Vehicle的具体类Car
class Car: public Vehicle
{
public:
virtual void run() const
{
std::cout << "run a car
";
}
};

// 派生于Vehicle的具体类Airplane
class Airplane: public Vehicle
{
public:
virtual void run() const
{
std::cout << "run a airplane
";
}
};
客户程序可以通过指向基类Vehicle的指针(或引用)来操纵具体对象。通过指向基类对象的指针(或引用)来调用一个虚函数,会导致对被指向的具体对象之相应成员的调用:

// dynamic_poly_1.cpp

#include <iostream>
#include <vector>
#include "dynamic_poly.h"

// 通过指针run任何vehicle
void run_vehicle(const Vehicle* vehicle)
{
vehicle->run(); // 根据vehicle的具体类型调用对应的run()
}

int main()
{
Car car;
Airplane airplane;
run_vehicle(&car); // 调用Car::run()
run_vehicle(&airplane); // 调用Airplane::run()
}

此例中,关键的多态接口元素为虚函数run()。由于run_vehicle()的参数为指向基类Vehicle的指针,因而无法在编译期决定使用哪一个版本的run()。在运行期,为了分派函数调用,虚函数被调用的那个对象的完整动态类型将被访问。这样一来,对一个Car对象调用run_vehicle(),实际上将调用Car::run(),而对于Airplane对象而言将调用Airplane::run()。
或许动态多态最吸引人之处在于处理异质对象集合的能力:

// dynamic_poly_2.cpp

#include <iostream>
#include <vector>
#include "dynamic_poly.h"

// run异质vehicles集合
void run_vehicles(const std::vector<Vehicle*>& vehicles)
{
for (unsigned int i = 0; i < vehicles.size(); ++i)
{
vehicles[i]->run(); // 根据具体vehicle的类型调用对应的run()
}
}

int main()
{
Car car;
Airplane airplane;
std::vector<Vehicle*> v; // 异质vehicles集合
v.push_back(&car);
v.push_back(&airplane);
run_vehicles(v); // run不同类型的vehicles
}
在run_vehicles()中,vehicles[i]->run()依据正被迭代的元素的类型而调用不同的成员函数。这从一个侧面体现了面向对象编程风格的优雅。

静态多态

如果说动态多态是通过虚函数来表达共同接口的话,那么静态多态则是通过“彼此单独定义但支持共同操作的具体类”来表达共同性,换句话说,必须存在必需的同名成员函数。
我们可以采用静态多态机制重写上一节的例子。这一次,我们不再定义vehicles类层次结构,相反,我们编写彼此无关的具体类Car和Airplane(它们都有一个run()成员函数):

// static_poly.h

#include <iostream>

//具体类Car
class Car
{
public:
void run() const
{
std::cout << "run a car
";
}
};

//具体类Airplane
class Airplane
{
public:
void run() const
{
std::cout << "run a airplane
";
}
};

run_vehicle()应用程序被改写如下:

// static_poly_1.cpp

#include <iostream>
#include <vector>
#include "static_poly.h"

// 通过引用而run任何vehicle
template <typename Vehicle>
void run_vehicle(const Vehicle& vehicle)
{
vehicle.run(); // 根据vehicle的具体类型调用对应的run()
}

int main()
{
Car car;
Airplane airplane;
run_vehicle(car); // 调用Car::run()
run_vehicle(airplane); // 调用Airplane::run()
}
现在Vehicle用作模板参数而非公共基类对象(事实上,这里的Vehicle只是一个符合直觉的记号而已,此外别无它意)。经过编译器处理后,我们最终会得到run_vehicle<Car>()和 run_vehicle<Airplane>()两个不同的函数。这和动态多态不同,动态多态凭借虚函数分派机制在运行期只有一个run_vehicle()函数。
我们无法再透明地处理异质对象集合了,因为所有类型都必须在编译期予以决定。不过,为不同的vehicles引入不同的集合只是举手之劳。由于无需再将集合元素局限于指针或引用,我们现在可以从执行性能和类型安全两方面获得好处:

// static_poly_2.cpp

#include <iostream>
#include <vector>
#include "static_poly.h"

// run同质vehicles集合
template <typename Vehicle>
void run_vehicles(const std::vector<Vehicle>& vehicles)
{
for (unsigned int i = 0; i < vehicles.size(); ++i)
{
vehicles[i].run(); // 根据vehicle的具体类型调用相应的run()
}
}

int main()
{
Car car1, car2;
Airplane airplane1, airplane2;

std::vector<Car> vc; // 同质cars集合
vc.push_back(car1);
vc.push_back(car2);
//vc.push_back(airplane1); // 错误:类型不匹配
run_vehicles(vc); // run cars

std::vector<Airplane> vs; // 同质airplanes集合
vs.push_back(airplane1);
vs.push_back(airplane2);
//vs.push_back(car1); // 错误:类型不匹配
run_vehicles(vs); // run airplanes
}

两种多态机制的结合使用

在一些高级C++应用中,我们可能需要结合使用动态多态和静态多态两种机制,以期达到对象操作的优雅、安全和高效。例如,我们既希望一致而优雅地处理vehicles的run问题,又希望“安全而高效”地完成给飞行器(飞机、飞艇等)进行“空中加油”这样的高难度动作。为此,我们首先将上面的vehicles类层次结构改写如下:

// dscombine_poly.h

#include <iostream>
#include <vector>

// 公共抽象基类Vehicle
class Vehicle
{
public:
virtual void run() const = 0;
};

// 派生于Vehicle的具体类Car
class Car: public Vehicle
{
public:
virtual void run() const
{
std::cout << "run a car
";
}
};

// 派生于Vehicle的具体类Airplane
class Airplane: public Vehicle
{
public:
virtual void run() const
{
std::cout << "run a airplane
";
}

void add_oil() const
{
std::cout << "add oil to airplane
";
}
};

// 派生于Vehicle的具体类Airship
class Airship: public Vehicle
{
public:
virtual void run() const
{
std::cout << "run a airship
";
}

void add_oil() const
{
std::cout << "add oil to airship
";
}
};

我们理想中的应用程序可以编写如下:

// dscombine_poly.cpp

#include <iostream>
#include <vector>
#include "dscombine_poly.h"

// run异质vehicles集合
void run_vehicles(const std::vector<Vehicle*>& vehicles)
{
for (unsigned int i = 0; i < vehicles.size(); ++i)
{
vehicles[i]->run(); // 根据具体的vehicle类型调用对应的run()
}
}

// 为某种特定的aircrafts同质对象集合进行“空中加油”
template <typename Aircraft>
void add_oil_to_aircrafts_in_the_sky(const std::vector<Aircraft>& aircrafts)
{
for (unsigned int i = 0; i < aircrafts.size(); ++i)
{
aircrafts[i].add_oil();
}
}

int main()
{
Car car1, car2;
Airplane airplane1, airplane2;

Airship airship1, airship2;
std::vector<Vehicle*> v; // 异质vehicles集合
v.push_back(&car1);
v.push_back(&airplane1);
v.push_back(&airship1);
run_vehicles(v); // run不同种类的vehicles

std::vector<Airplane> vp; // 同质airplanes集合
vp.push_back(airplane1);
vp.push_back(airplane2);
add_oil_to_aircrafts_in_the_sky(vp); // 为airplanes进行“空中加油”

std::vector<Airship> vs; // 同质airships集合
vs.push_back(airship1);
vs.push_back(airship2);
add_oil_to_aircrafts_in_the_sky(vs); // 为airships进行“空中加油”
}

我们保留了类层次结构,目的是为了能够利用run_vehicles()一致而优雅地处理异质对象集合vehicles的run问题。同时,利用函数模板add_oil_to_aircrafts_in_the_sky<Aircraft>(),我们仍然可以处理特定种类的vehicles — aircrafts(包括airplanes和airships)的“空中加油”问题。其中,我们避开使用指针,从而在执行性能和类型安全两方面达到了预期目标。

结语

长期以来,C++社群对于多态的内涵和外延一直争论不休。在comp.object这样的网络论坛上,此类话题争论至今仍随处可见。曾经有人将动态多态(dynamic polymorphism)称为inclusion polymorphism,而将静态多态(static polymorphism)称为parametric polymorphism或parameterized polymorphism。

我注意到2003年斯坦福大学公开的一份C++ and Object-Oriented Programming教案中明确提到了函数多态概念:Function overloading is also referred to as function polymorphism as it involves one function having many forms。文后的“参考文献”单元给出了这个网页链接。

可能你是第一次看到宏多态(macro polymorphism)这个术语。不必讶异 — 也许我就是造出这个术语的“第一人”。显然,带变量的宏(或类似于函数的宏或伪函数宏)的替换机制除了免除小型函数的调用开销之外,也表现出了类似的多态性。在我们上面的例子中,字符串相加所表现出来的符合直觉的连接操作,事实上是由底部运算符重载机制(operator overloading)支持的。值得指出的是,C++社群中有人将运算符重载所表现出来的多态称为ad hoc polymorphism。

David Vandevoorde和Nicolai M. Josuttis在他们的著作C++ Templates: The Complete Guide一书中系统地阐述了静态多态和动态多态技术。因为认为“和其他语言机制关系不大”,这本书没有提及“宏多态”(以及“函数多态”)。(需要说明的是,笔者本人是这本书的繁体中文版译者之一,本文正是基于这本书的第14章The Polymorphic Power of Templates编写而成)

动态多态只需要一个多态函数,生成的可执行代码尺寸较小,静态多态必须针对不同的类型产生不同的模板实体,尺寸会大一些,但生成的代码会更快,因为无需通过指针进行间接操作。静态多态比动态多态更加类型安全,因为全部绑定都被检查于编译期。正如前面例子所示,你不可将一个错误的类型的对象插入到从一个模板实例化而来的容器之中。此外,正如你已经看到的那样,动态多态可以优雅地处理异质对象集合,而静态多态可以用来实现安全、高效的同质对象集合操作。

静态多态为C++带来了泛型编程(generic programming)的概念。泛型编程可以认为是“组件功能基于框架整体而设计”的模板编程。STL就是泛型编程的一个典范。STL是一个框架,它提供了大量的算法、容器和迭代器,全部以模板技术实现。从理论上讲,STL的功能当然可以使用动态多态来实现,不过这样一来其性能必将大打折扣。

静态多态还为C++社群带来了泛型模式(generic patterns)的概念。理论上,每一个需要通过虚函数和类继承而支持的设计模式都可以利用基于模板的静态多态技术(甚至可以结合使用动态多态和静态多态两种技术)而实现。正如你看到的那样,Andrei Alexandrescu的天才作品Modern C++ Design: Generic Programming and Design Patterns Applied(Addison-Wesley)和Loki程序库已经走在了我们的前面。

继承、重载、覆盖、多态


#桓询钱# 多态是子类与父类允许有相同的变量名,不同的数据类型.我想问,能不能是相同的数据类型? -
(13843444002): 面向对象:封装、继承、多态.多态的表现形式: 我最初学的时候认为有两种:覆盖(定义与父类相同的变量和方法)和重载(在同一个类中定义多个方法名相同但参数不同的方法).现在我觉得多态的本质是:一个猴子(具体对象)可以称之为哺乳类,还可以称之为动物.

#桓询钱# 面向对象中的多态的理解 -
(13843444002): 简单来说,多态是具有表现多种形态的能力的特征,在OO中是指,语言具有根据对象的类型以不同方式处理之,特别是重载方法和继承类这种形式,的能力.多态被认为是面向对象语言的必备特性. 多态有多种分类,通过了解这些分类可以更...

#桓询钱# java里面的内部类,抽象类,还有对象的多态有点搞混了. -
(13843444002): /** * 内部类 只要知道是类内部的一个类就可以了 可以忽略 * 因为一般用不用都无所谓 * 抽象类和多态用的比较多 * 抽象类就是把问题给抽象化 * 例如我有一个类 就叫做Eat 里面一个eat方法 就是吃东西的动作 * 至于吃什么我现在还不确定 * 当...

#桓询钱# 什么是多态函数
(13843444002): 多态性就是多种表现形式,具体来说,可以用"一个对外接口,多个内在实现方法"表示.举一个例子,计算机中的堆栈可以存储各种格式的数据,包括整型,浮点或字符.不管存储的是何种数据,堆栈的算法实现是一样的.针对不同的数据类...

#桓询钱# 什么是面向对象中的多态?在Java中有哪些实现方式? -
(13843444002): 多态是指若干个属于不同类的对象实例,对于同一个消息(如方法调用)做出的不一样的应答方式.JAVA多态性的实现主要有:继承多态、抽象多态、接口多态.

#桓询钱# 在一个类中对象的表现形式有哪些 -
(13843444002): “所见即所得”的编程思想为原则,力图实现编程工作的可视化,即随时可以看到结果,程序与结果的调整同步. 可视化编程是与传统的编程方式相比而言的,这里的“可视”,指的是无须编程,仅通过直观的操作方式即可完成界面的设计工作...

#桓询钱# c++中什么是多态! -
(13843444002): 在C++中接口的多种不同的实现方式就是多态. 多态性是允许你将父对象设置成为一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作.允许将子类类型的指针赋值给父类类型的指...

#桓询钱# java中多态是什么意思? -
(13843444002): 2L人家问的是多态,不是重载 你就把多态当成用父类引用子类就好了 比如有一个类A,类B,C都继承它 那么可以A a1 = new B(); A a2 = new C(); 这样,至于为什么这样做,现在不用急着理解,以后慢慢编程的过程中自己会体会到的

#桓询钱# 使用继承,可以使类之间产生关系,提供了多态的特性.? -
(13843444002): 简单来说,多态是具有表现多种形态的能力的特征,在OO中是指,语言具有根据对象的类型以不同方式处理之,特别是重载方法和继承类这种形式,的能力.多态被认为是面向对象语言的必备特性.多态有多种分类,通过了解这些分类可以更...

#桓询钱# 什么是多态函数
(13843444002): 多态性就是多种表现形式,具体来说,可以用"一个对外接口,多个内在实现方法"表示.举一个例子,计算机中的堆栈可以存储各种格式的数据,包括整型,浮点或字符.不管存储的是何种数据,堆栈的算法实现是一样的.针对不同的数据类...