“多态”的关键在于通过基类指针或引用调用一个虚函数时,编译时不确定到底调用的是基类还是派生类的函数,运行时才确定。例子:

#include<iostream>
using namespace std;
class A{
public:
int i;
virtual void func(){};
virtual void func2(){};   //如果为只有一个去掉 virtual 关键字即virtual void func2(){};变为 void func2(){}; 输出结果不变 仍为 8,12
}; //当 virtual 关键字都去掉时,结果才为 4,8
class B :public
int j;
void func(){}
};
int main(){
cout<<sizeof(A)<<","<<sizeof(B);
};

  输出结果:

8,12

  如果将程序中的 virtual 关键字去掉:

#include<iostream>
using namespace std;
class A{
public:
int i;
void func(){};
void func2(){};
};
class B :public A{
int j;
void func(){}
};
int main(){
cout<<sizeof(A)<<","<<sizeof(B);
};

  输出结果:

4,8

  对比发现,有了虚函数以后,对象占用的存储空间比没有虚函数时多了4个字节。实际上,任何有虚函数的类及其派生类的对象都包含这多出来的4个字节,这4个字节就是实现多态的关键——它位于对象存储空间的最前端,其中存放虚函数表的地址。

  每一个有虚函数的类(或有虚函数的类的派生类)都有一个虚函数表,该表的任何对象中都放着该虚函数表的指针(可以认为这是由编译器自动添加到构造函数中的指令完成的)。虚函数表是编译器生成的,程序运行时被载入内存。一个类的虚函数表中列出了该类的全部虚函数地址。例如,在上面的程序中,类A对象的存储空间以及虚函数表(假定类A还有其他虚函数)如图

  类B对象的存储空间以及虚函数表(假定类B还有其他虚函数)如图

  多态的函数调用语句被编译成根据基类指针所指向的(或基类引用所引用的)对象中存放的虚函数表的地址,在虚函数表中查找虚函数地址,并调用虚函数的一系列指令。

  假设pa的类型是A*,则pa->func()这条语句的执行过程如下:

    (1)取出pa指针所指位置的前4个字节,即对象所属的类的虚函数表的地址(在64位计算机中,由于指针占8个字节,所以要取出8个字节)。如果pa指向的是类A的对象,则这个地址就是类A的虚函数表的地址;如果pa指向的是类B的对象,则这个地址就是类B的虚函数表的地址。

    (2)根据虚函数表的地址找到虚函数表,在其中查找要调用的虚函数的地址。不妨认为虚函数表是以函数名作为索引来查找的,虽然还有更高效的查找方法。如果pa指向的是类A的对象,自然就会在类A的虚函数表中查找A::func的地址;如果pa指向的是类B的对象,就会在类B的虚函数表中查出B::func的地址。类B没有自己的func2函数,因此在类B的虚函数表中保存的是A::func2的地址,这样,即便pa指向类B的对象,"pa->func2();"这条语句在执行过程中也能在类B的虚函数表中找到A::func2的地址。

    (3)根据找到的虚函数的地址调用虚函数。

  由以上过程可以看出,只要是通过基类指针或基类引用调用虚函数的语句,就一定是多态的。也一定会执行上面的查表过程,哪怕这个虚函数仅在基类中有,在派生类中没有。

新标准c++程序设计

多态实现的原理------新标准c++程序设计的更多相关文章

  1. 在成员函数中调用虚函数(关于多态的注意事项)------新标准c++程序设计

    类的成员函数之间可以互相调用.在成员函数(静态成员函数.构造函数和析构函数除外)中调用其他虚成员函数的语句是多态的.例如: #include<iostream> using namespa ...

  2. 多态的作用-游戏编程展示------新标准c++程序设计

    游戏软件的开发最能体现面向对象设计方法的优势.游戏中的人物.道具.建筑物.场景等都是很直观的对象,游戏运行的过程就是这些对象相互作用的过程.每个对象都有自己的属性和方法,不同对象也可能有共同的属性和方 ...

  3. 正确处理类的复合关系------新标准c++程序设计

    假设要编写一个小区养狗管理程序,该程序需要一个“主人”类,还需要一个“狗”类.狗是有主人的,主人也有狗.假定狗只有一个主人,但一个主人可以有最多10条狗.该如何处理“主人”类和“狗”类的关系呢?下面是 ...

  4. 类与类之间的两种关系------新标准c++程序设计

    在c++中,类和类之间有两种基本关系:复合关系和继承关系. 复合关系也称为“has a”关系或“有”的关系,表现为封闭类,即一个类以另一个类的对象作为成员变量. 继承关系也称为“is a”关系或“是” ...

  5. 复制构造函数被调用的三种情况------新标准c++程序设计

    1.当用一个对象去初始化同类的另一个对象时,会引发复制构造函数被调用.例如,下面的两条语句都会引发复制构造函数的调用,用以初始化c2. C c2 (c1); C c2=c1; 这两条语句是等价的.注意 ...

  6. 析构函数的调用------新标准c++程序设计

    示例1: #include<iostream> using namespace std; class CDemo{ public: ~CDemo(){cout<<"d ...

  7. 类型转换构造函数 及使用explicit避免类型自动转换------新标准c++程序设计

    类型转换构造函数:  除复制构造函数外,只有一个参数的构造函数一般可以称作类型转换构造函数,因为这样的构造函数能起到类型自动转换的作用.例如下面的程序: #include<iostream> ...

  8. this指针------新标准c++程序设计

    背景:   c++是在c语言的基础上发展而来的,第一个c++的编译器实际上是将c++程序翻译成c语言程序,然后再用c语言编译器进行编译.c语言没有类的概念,只有结构,函数都是全局函数,没有成员函数.翻 ...

  9. 类的互相包含------新标准c++程序设计

    #include<iostream> using namespace std; class A; class B{ public: void f(A* pt){}; } class A{ ...

随机推荐

  1. 登陆验证系统实例-三种(cookie,session,auth)

    登陆验证 因为http协议是无状态协议,但是我们有时候需要这个状态,这个状态就是标识 前端提交from表单,后端获取对应输入值,与数据库对比,由此对象设置一个标识,该对象 在别的视图的时候,有此标识, ...

  2. activemq安装运行及其在springboot中的queue和topic使用

    安装activemq 运行 springboot使用 依赖 配置 Producer Consumer ComsumerTopic 使用 安装activemq http://activemq.apach ...

  3. 匿名类型与Select方法实现自定义对象插入局部表结构中

    在提取局部表结构数据时,通过Select选取需要的字段,如下句,此时其实产生了一个不用于_menuMan的原新数据类型new { c.SYS_COMMANDS_ID,c.TXT_COMMANDTITL ...

  4. Java ThreadPoolExecutor线程池原理及源码分析

    一.源码分析(基于JDK1.6) ThreadExecutorPool是使用最多的线程池组件,了解它的原始资料最好是从从设计者(Doug Lea)的口中知道它的来龙去脉.在Jdk1.6中,Thread ...

  5. 第一次调用Web service响应速度慢的解决办法

    Env: Client: WinForm(Net Framework 2.0) Server:Web Service(Net Framework 4.0) Problem: Client use pr ...

  6. python:if 语句的使用方法

    if-else类型: #if-else num = int(input("输入成绩!")) if num > 60: print ("及格") else: ...

  7. 尝试在centos5下运行phantomjs2

    在redhat5上运行plantomjs 2,出现如下错误 bin/phantomjs: /lib64/libz.so.1: no version information available (req ...

  8. linux上的第一个c语言程序

    1.编辑源文件 输入命令如下: root@ubuntu:/home/amy# vi hello.c 文件内容如下: #include<stdio.h> int main() { print ...

  9. Effective ObjectiveC 2.0 Note

    [Effective ObjectiveC 2.0 Note] 1.The memory for objects is always allocated in heap space and never ...

  10. json_encode和json_decode和isset和array_key_exists

    1.json_decode() json_decode — 对 JSON 格式的字符串进行编码         说明 mixed json_decode ( string $json [, bool ...