文档章节

C++多态是如何实现的——一个简单明晰的例子告诉你!

木兰宿莽
 木兰宿莽
发布于 2016/11/17 22:24
字数 1210
阅读 21
收藏 2
点赞 0
评论 0

先弄清楚几个概念:

1.C++多态依靠虚函数来实现;
2.凡是类中有带关键字virtual的函数均属于虚函数,如下:

class A
{
public:
   void f(){}  //--->普通成员函数
public:
   virtual void f1(void){...}  //---> 虚函数
   virtual void f2(void)=0;    //---> 纯虚函数
};

3.虚函数没有实体部分,即没有函数体而是等于零,则为纯虚函数。
4.拥有纯虚函数的类不能直接定义对象,如下报错:

int main()
{
  A a;//--->错误
return 0;
}

5.继承类需要定义纯虚函数实体才能定义对象,如下:

class B:public A
{
public:
   f2(void){
      //do something
   }
};
int main()
{
  B b;//--->正确
return 0;
}

6.虚函数一般是public成员函数,除非有特别的用处。

什么叫做虚函数表(vtables):
    虚函数表是一块连续的内存,每个内存单元中记录一个JMP指令的地址。
虚函数表属于类而不是具体对象,对不同的编译器其实现有所不同,比方
windows虚函数表放在常量段空间中,而linux/unix则放在只读数据段当中。
(引用别处说法,没有考证)
什么叫做虚函数指针(vptrs):
    每一个由有虚函数生成的对象包含指向虚函数的指针,注意不同对象的指

针地址不同,即指向不同(这里不同对象是指继承了具有虚函数基类的子类

所生成的对象),正是由于每个对象的虚函数指针指向的是自己对应类所实

现的函数,因此调用时对应的是子类对象的具体函数实现,从而完成了多态的
实现。

#include "stdafx.h"
#include<iostream>
#include<cmath>
#include<ctime>
#include<windows.h>
using namespace std;
enum Color
{
Red,
Black,
Yellow,
Orange,
Brown,
White
};
class Shape
{
protected:
   double xPos;
   double yPos;
   Color color;
public:
   Shape(double x=0.0f,double y=0.0f,Color c=White):xPos(x),yPos(y),color(c){}
   ~Shape(){}
protected:
public:
   virtual void setColor(Color)=0;
   virtual Color getColor()=0;
   virtual bool drawShape(double,double)=0;
   virtual void setPosition(double,double)=0;
   virtual void movePosition(double,double)=0;
   virtual void erase()=0;
   virtual void showShape()=0;
};
class Circle:public Shape
{
private:
   double radius;
public:
   Circle(double r=1.0f):radius(r),Shape(){}
   ~Circle(){}
public:
   double getRadius(){
     return radius;
   }
   void setPosition(double x=0.0f,double y=0.0f){
     xPos=x;
     yPos=y;
   }
   bool drawShape(double x=0.0f,double y=0.0f){return true;}
   void movePosition(double x=0.0f,double y=0.0f){}
   void erase(){}
   void showShape(){ //画一个半径为radius的圆
     for(double yv=this->radius;yv>=-this->radius;yv-=0.1f){
       for(double xv=this->radius;xv>=-this->radius;xv-=0.05f){
          if(sqrt(pow(xv,2)+pow(yv,2))<=this->radius){
             cout<<"*";
          }
          else{
            cout<<" ";
          }
       }
         endl(cout);
     }
   }
   Color getColor(){
     return Shape::color;
   }
   void setColor(Color c=Red){
   }
};

class Rectangle1:public Shape
{
private:
   double length;
   double width;
public:
   Rectangle1(double l=2.0f,double w=1.0f,double x=0.0f,double y=0.0f):length(l),width(w),Shape(x,y){}
   ~Rectangle1(){}
public:
   void setPosition(double x=0.0f,double y=0.0f){
     xPos=x;
     yPos=y;
   }   
   bool drawShape(double x=0.0f,double y=0.0f){ return true;}
   void movePosition(double x=0.0f,double y=0.0f){
      xPos+=x;
      yPos+=y;
   }
   void erase(){}
   void showShape(){ //画一个长宽为xv和yv的长方形
      for(double yv=0.0f;yv<=yPos+width;yv+=0.05f){
        for(double xv=0.0f;xv<=xPos+length;xv+=0.05f){
           if(yv>=yPos&&xv>=xPos)cout<<"*";
	   else cout<<" ";
        }
       endl(cout);
     }
   }
   void setColor(Color c=Red){
   }
   Color getColor(){
     return Shape::color;
   }
};
int _tmain(int argc, _TCHAR* argv[])
{
   Shape* shape;
   while(true){
   for(int i=1;i<=3;i++){
     shape=new Circle(i*0.5f);
     shape->showShape(); //通过虚函数表调用Circle类的showShape函数
     Sleep(500);
     delete shape;
     shape=new Rectangle1(0.3f*i,0.3f*i,0.3f*i,0.3f*i);
     shape->showShape(); //通过虚函数表调用Rectangle1类的showShape函数
     delete shape;
   }
 }
}

运行如下:

结语:
在大型的软件工程中,类的继承关系相当复杂庞大,在这样的情况下虚函数可以说
有了极大的用武之地了,一层层的继承关系,每个子类对虚函数都会做具体的实现
通过父类指针来调用这些函数可以在不同的代码段中实现不同的功能,极大的方便
了编程,而且让人感觉有点"智能"。
如shape调用Circle类的showShape函数来画一个圆,而调用Rectangle1类的showShape
函数来画一个长方形。这是一个简单的例子,形状有各种各样,但是shape指针可以分别
调用不同对象的showShape函数,加上不同的参数,便可以画出形形色色的图案。
试想,若没有这种多态机制,那么一定需要在具体的对象的指针各自调用各自的showShape
函数,这样即不利于编程,而且失去了父类指针统一调度各个类对象的函数的机制。

© 著作权归作者所有

共有 人打赏支持
木兰宿莽
粉丝 34
博文 12
码字总数 9318
作品 0
崇明
程序员
C中的继承和多态

2010-09-23 00:27 by 吴秦,19167 阅读,23 评论,收藏,编辑 1、引言 继承和多态是面向对象语言最强大的功能。有了继承和多态,我们可以完成代码重用。在C中有许多技巧可以实现多态。本文的目的...

老朱教授
2017/11/26
0
0
绕开“陷阱“,阿里专家带你深入理解C++对象模型的特殊之处

摘要:本文介绍了C++对象模型的特殊之处,包括与C兼容的朴素模型,以及能支持多态的虚表模型,同时还带大家了解了构造函数与析构函数相关的一些特性与陷阱。这些内容能够帮助大家更好地学习和...

nirvanalucky
04/25
0
0
C++项目中的extern "C" {}

引言 在用C++的项目源码中,经常会不可避免的会看到下面的代码: 1 2 3 4 5 6 7 8 9 #ifdef cplusplus extern "C" { #endif /.../ #ifdef cplusplus } #endif 它到底有什么用呢,你知道吗?而...

暖冰
2015/11/20
0
0
C语言/C++编程学习—神奇设计模式代码之群星

C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到...

小辰带你看世界
03/26
0
0
GCC 用 C++ 来编译(酷壳)

GCC在2012年8月15日的时候,merge了一个patch - Merge from cxx-conversion branch,这意味着,以后在GCC的编译只能用C++的编译器了,也意味着,gcc的实现代码开始转向C++了。 你可能会有两个...

j_m
2012/10/22
0
0
面向对象编程 (封装,继承,多态or组件,接口)

Function/bind可以是一个很简单的话题,因为它其实不过就是一个泛型的函数指针。但是如果那么来谈,就没意思了,也犯不上写这篇东西。在我看来,这个事情要讲的话,就应该讲透,讲到回调(c...

_夏天的风_
2015/05/18
0
1
【C++程序设计技巧】NVI(Non-Virtual Interface )

在C++的程序设计中有一些设计开发的典型技巧需要整理讨论,在此抛砖引玉,为自己做积累,请高人也多多指教。 1.简介 在标准C++库中我们可以看到这样的一个现象: 6个公有虚函数,并且都是std...

老朱教授
2017/11/26
0
0
三好学生Chris Lattner的LLVM编译工具链

2011年12月3日,LLVM 3.0正式版发布,完整支持所有ISO C++标准和大部分C++ 0x的新特性, 这对于一个短短几年的全新项目来说非常不易。 开发者的惊愕 在2011年WWDC(苹果全球开发者大会)的一...

Rifle
2012/11/16
0
0
篮子、水果和鸡蛋——关于C++的模板偏特化和萃取编程技法

最近在读《STL源码剖析》。读这本书的时候发现自己的C++的知识其实是非常匮乏的。 从大学的C++教材上学到一些C++基本的语法、内存管理、继承、多态等方面的基础知识。这些只是是一棵大树的根...

costaxu
2012/12/22
0
0
android开发教程(3)— jni编程之采用SWIG从Java调用C/C++

Android 从Java调用C/C++ 当无法用 Java 语言编写整个应用程序时,JNI 允许您调用C/C++本机代码。在下列典型情况下,您可能决定使用本机代码: 希望用更低级、更快的编程语言C/C++去实现对时...

刘小米
2014/09/16
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

java 复制对象有哪些方式

java 复制对象有哪些方式 Apache的 Common beanutils库 org.apache.commons.beanutils.BeanUtils.copyProperties(dest,origin); Springframework 的BeanUtil 依赖: <dependency> ......

黄威
11分钟前
0
0
1.13 单用户模式

命令 init 6 #重启,reboot或shutdown -r now init 0 #重启,poweroff 单用户模式:密码忘记情况下 主机重启,按方向键↑,选择CentOS Linux (3.10.0-514.e17.X86 64) 7 (Core),按e键编辑...

小丑鱼00
13分钟前
0
0
jstack的简单使用

公司测试反应, 一个java应用的机器,cpu始终是30%, 即使不做交易, 于是想到了之前看到的jstack文章, 实践步骤记录一下: 1, 找出java应用的进程号 ps -ef|grep 应用名|grep -v grep 2, 找出pid...

零二一七
18分钟前
0
0
崛起于Springboot2.X之项目war打包部署(18)

将springboot项目打包步骤: 1、启动类 extends SpringBootServletInitializer 2、启动类添加覆盖方法 @Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder......

木九天
27分钟前
0
0
导入CSV文件就行数据整理分析

#-*-coding:utf-8-*-import csv,os,re,mathlocalPath=input("请输入所有群文件的根目录:") #所有QQ群文件的物理根目录路径def info(): info_dic=[] dirList=os.listdi...

Kefy
33分钟前
0
0
CoreText进阶(六)-内容大小计算和自动布局

CoreText进阶(六)-内容大小计算和自动布局 其它文章: CoreText 入门(一)-文本绘制 CoreText入门(二)-绘制图片 CoreText进阶(三)-事件处理 CoreText进阶(四)-文字行数限制和显示更...

aron1992
34分钟前
0
0
一个Unity高人的博客,涉猎范围很广,深度也很深。

https://blog.csdn.net/ecidevilin/article/list/

爽歪歪ES
36分钟前
0
0
Spring Cloud Config-Git后端

EnvironmentRepository的默认实现使用Git后端,这对于管理升级和物理环境以及审核更改非常方便。要更改存储库的位置,可以在Config Server中设置“spring.cloud.config.server.git.uri”配置...

itcloud
38分钟前
1
0
centos7 卸载mysql

[root@zyf ~]# rpm -qa|grep -i mysqlmysql-community-libs-5.6.34-2.el7.x86_64mysql-community-server-5.6.34-2.el7.x86_64mysql-community-release-el7-5.noarchmysql-community-......

Yao--靠自己
46分钟前
0
0
【Spring 系列 条件注解】

Spring 提供了按条件注册Bean的功能涉及到两个组件分别是:核心接口Condition,核心注解Conditional。 1、示例说明 为了演示条件注解的效果,需要定义一个属性文件,然后根据属性文件中配置的...

HansonReal
54分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部