c++ 的多态是如何实现的!!!

zlaxr8888 2009-10-28 08:55:19
如题,
...全文
5168 38 打赏 收藏 转发到动态 举报
写回复
用AI写文章
38 条回复
切换为时间正序
请发表友善的回复…
发表回复
tanchunwu 2011-10-14
  • 打赏
  • 举报
回复
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;

class A
{
public:
A(){}
~A(){}
virtual void Print()
{
cout<<"A Print"<<endl;
}
};

class B: public A
{
public:
B(){}
~B(){}
void Print()
{
cout<<"B Print"<<endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A *p = new A;
p->Print(); //p指向A,所以调用A中方法
p = new B;
p->Print(); //p指向B,所以调用B中方法
system("pause");
return 0;
}
输出
A Print
B Print

ang_biwen 2011-05-13
  • 打赏
  • 举报
回复 1
通过虚函数和指针来实现。创建一个基类指针,当它指向不同的对象时,调用的虚函数也不同,这就是多态。
cae213 2011-05-13
  • 打赏
  • 举报
回复
谢谢!
zengsheng2619 2011-05-13
  • 打赏
  • 举报
回复
虚函数表
zldrobit 2011-05-13
  • 打赏
  • 举报
回复
上边的各位已经说的很清楚了,如果楼主想了解更多关于C语言实现面向对象的东东,可以看看我博客哟

里边用C语言实现了虚函数的功能。。。。
http://blog.csdn.net/zldrobit/archive/2011/05/12/6415143.aspx
tzg_dzq 2011-01-13
  • 打赏
  • 举报
回复
//基类
class BaseClassTest
{
public:
BaseClassTest(){cout<<"BaseClassTest"<<endl;}
virtual ~BaseClassTest(){cout<<"~BaseClassTest"<<endl;}

virtual void Dis(void) {cout<<"BaseClassTest::Dis"<<endl;}
};
//派生类
class DerivativeClassTest : public BaseClassTest
{
public:
DerivativeClassTest(){cout<<"DerivativeClassTest"<<endl;}
virtual ~DerivativeClassTest(){cout<<"~DerivativeClassTest"<<endl;}
virtual void Dis(void){cout<<"DerivativeClassTest::Dis"<<endl;}
};
//main
BaseClassTest *pbct = new BaseClassTest;

pbct->Dis();
pbct = new DerivativeClassTest;
pbct->Dis();

//输出
BaseClassTest
BaseClassTest::Dis
BaseClassTest
DerivativeClassTest
DerivativeClassTest::Dis
Press any key to continue . . .
mtj530 2011-01-13
  • 打赏
  • 举报
回复

[Quote=引用 24 楼 suifengme 的回复:]
面向对象程序设计中的另外一个重要概念是多态性。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。可以把一组对象放到一个数组中,然后调用它们的方法,在这种场合下,多态性作
用就体现出来了,这些对象不必是相同类型的对象。当然,如果它们都继承自某个类,你可以把这些派生类,都放到一个数组中。如果这些对象都有同名方法,就可以调用每个对象的同名方法。

同一操作作用于不同的对象,可以有不同的……
[/Quote]+1
未注销 2011-01-12
  • 打赏
  • 举报
回复
看下书吧。
todhacker111 2011-01-12
  • 打赏
  • 举报
回复
可以到我的CSDN博客看看。里面有详细介绍
xzjxylophone 2011-01-12
  • 打赏
  • 举报
回复
google 百度 bing下。
ww884203 2011-01-12
  • 打赏
  • 举报
回复
虚函数表,看《Inside the C++ object model》
我在地球 2011-01-12
  • 打赏
  • 举报
回复
虚函数 重载
ningweidong 2011-01-12
  • 打赏
  • 举报
回复
这种理论性的东西,不是几句话你就明白的。
多态是通过虚函数来实现的
na2650945 2011-01-12
  • 打赏
  • 举报
回复
虚函数表。
Inside C++ Object Model
极客代码 2011-01-12
  • 打赏
  • 举报
回复
面向对象程序设计中的另外一个重要概念是多态性。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。可以把一组对象放到一个数组中,然后调用它们的方法,在这种场合下,多态性作
用就体现出来了,这些对象不必是相同类型的对象。当然,如果它们都继承自某个类,你可以把这些派生类,都放到一个数组中。如果这些对象都有同名方法,就可以调用每个对象的同名方法。

同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。多态性通过派生类重载基类中的虚函数型方法来实现。

在面向对象的系统中,多态性是一个非常重要的概念,它允许客户对一个对象进行操作,由对象来完成一系列的动作,具体实现哪个动作、如何实现由系统负责解释。

“多态性”一词最早用于生物学,指同一种族的生物体具有相同的特性。在C#中,多态性的定义是:同一操作作用于不同的类的实例,不同的类将进行不同的解释,最后产生不同的执行结果。C#支持两种类型的多态性:

● 编译时的多态性

编译时的多态性是通过重载来实现的。对于非虚的成员来说,系统在编译时,根据传递的参数、返回的类型等信息决定实现何种操作。

● 运行时的多态性

运行时的多态性就是指直到系统运行时,才根据实际情况决定实现何种操作。C#中,运行时的多态性通过虚成员实现。

编译时的多态性为我们提供了运行速度快的特点,而运行时的多态性则带来了高度灵活和抽象的特点。


多态 - “虚函数”(或者是“虚方法”)
虚函数就是允许被其子类重新定义的成员函数。而子类重新定义父类虚函数的做法,称为“覆盖”(override),或者称为“重写”。
多态 - 多态的作用
把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。   赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。也就是说,父亲的行为像儿子,而不是儿子的行为像父亲。   举个例子:从一个基类中派生,响应一个虚命令,产生不同的结果。   比如从某个基类继承出多个对象,其基类有一个虚方法Tdoit,然后其子类也有这个方法,但行为不同,然后这些子对象中的任何一个可以附给其基类的对象,这样其基类的对象就可以执行不同的操作了。实际上你是在通过其基类来访问其子对象的,你要做的就是一个赋值操作。   使用继承性的结果就是可以创建一个类的家族,在认识这个类的家族时,就是把导出类的对象 当作基类的的对象,这种认识又叫作upcasting。这样认识的重要性在于:我们可以只针对基类写出一段程序,但它可以适 应于这个类的家族,因为编译器会自动就找出合适的对象来执行操作。这种现象又称为多态性。而实现多态性的手段又叫称动态绑定(dynamic binding)。   简单的说,建立一个父类的变量,它的内容可以是这个父类的,也可以是它的子类的,当子类拥有和父类同样的函数,当使用这个变量调用这个函数的时候,定义这个变量的类,也就是父类,里的同名函数将被调用,当在父类里的这个函数前加virtual关键字,那么子类的同名函数将被调用.

"重载"和“重写”是实现多态的两种方法:
“重载”是指在同一个类中相同的返回类型和方法名,但是参数的个数和类型可以不同;
“重写”是指在不同的类中。



1、C++多态如何实现

重载overload是相同范围内,函数名相同,参数不同;

覆盖override不同范围内(派生类和基类),函数名相同,参数也相同,基类函数必须有virtual关键字;

重载的意义在于针对同一函数调用提供了多种可选版本;

而覆盖一般是指派生类的成员函数去覆盖基类的(同名)成员函数,使在派生类的作用域内只有派生类自己那个成员函数可见,而要调用基类的同名函数,则需提供显示的域解析符::

多态是指用指向基类指针调用虚函数时,总能调用到正确的版本。也就是说,如果基类指针实际指向的是某个派生类对象,而这个派生类又覆盖了基类中定义的相应的虚函数,那么通过这个指针调用的成员函数,就是(所期望的)派生类自己定义的那个成员函数。



补充一下,刚看到一个隐藏的概念,跟覆盖区别一下
令人迷惑的隐藏规则
本来仅仅区别重载与覆盖并不算困难,但是C++的隐藏规则使问题复杂性陡然增加。
这里“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual
关键字,基类的函数将被隐藏(注意别与重载混淆)。
(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual
关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。

2、
sys_brk支持c语言的 malloc和free函数 低级操作。malloc通过 调用sys_brk向内核申请一段虚拟地址空间 vma(线性区),建立地址映射,vma全部建立起与内存页的映射──通过mmap实现;free也通过这个系统调用告诉内核需要收回这个线性地址空间,取消已经建立的映射 。
sys_brk系统调用可以对用户进程的堆的大小进行操作,使堆扩展或者缩小。

1)
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,
会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序──即由内核的空闲区变成进程的线性区,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
2)
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域(在 WINDOWS下,栈的大小是2M)
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。(堆的大小受限于计算机系统中有效的虚拟内存)
3)
栈由系统自动分配,速度较快。但程序员是无法控制的。
堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.
另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活

3
内核提供了kmalloc和kfree,分配真实地址已知的实际物理内存块,──映射到连续物理页框

还提供了vmalloc和vfree,用于对内核使用的虚拟内存进行分配和释放。vamalloc分配的虚拟地址空间在3G+high_memory+VMALLOC_OFFSET以上的高端,由vmlist链表管理。 3G是内核态访问物理内存的起始地址,high_memory是计算机实际可用的物理内存的最高地址,VMALLOC_OFFSET是8M的“隔离带”──映射到 非连续物理页框。

Julykey 2009-11-09
  • 打赏
  • 举报
回复
指针和引用,这两个是运行时多态的基石
super_chris 2009-11-09
  • 打赏
  • 举报
回复
笔误。。。怎么出来函数指针了
是对象指针。。。[Quote=引用 21 楼 super_chris 的回复:]
说本质应该是延迟绑定
如果考试应该答虚函数 函数指针什么的吧
[/Quote]
super_chris 2009-11-09
  • 打赏
  • 举报
回复
说本质应该是延迟绑定
如果考试应该答虚函数 函数指针什么的吧
小麻侬 2009-11-09
  • 打赏
  • 举报
回复
虚函数,然后用父类指针或引用指向子类,可以参考<<c++ primer>>里的详细介绍
leaker 2009-11-09
  • 打赏
  • 举报
回复
虚函数来实现, 我觉得有两点重要
1)如果在派生类中重新定义基类的方法, 则将他设为虚函数, 否则为非虚函数
2)在基类方法的声明中使用关键字virtual可使该方法在基类以及所有派生类
包括从派生类派生出来的类的该方法也是虚的--基类
中是虚函数, 则派生类中的该函数也是虚函数, 无论派生类中该方法是否加
关键字virtual. 但是我们最好在派生类中为该函数也加上关键字virtual
加载更多回复(18)

64,661

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧