文档章节

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

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

先弄清楚几个概念:

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
函数,这样即不利于编程,而且失去了父类指针统一调度各个类对象的函数的机制。

© 著作权归作者所有

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

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

老朱教授
2017/11/26
0
0
C语言/C++编程学习—神奇设计模式代码之群星

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

小辰带你看世界
03/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
GCC 用 C++ 来编译(酷壳)

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

j_m
2012/10/22
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Java Web--增删改查之二界面后台java代码(转载参考)

/** *  *//** * @author Administrator * */package dao; import java.sql.*;public class DBConn {/** * 链接数据库 * @return */  ...

小橙子的曼曼
4分钟前
0
0
Redis源码阅读笔记-对象及其类型和编码

总结之《Redis设计与实现》 对象 Redis中是使用对象来便是数据库中的键和值。 结构 // server.h...#define LRU_BITS 24...typedef struct redisObject { unsigned type:4; ...

Jian_Ming
17分钟前
0
0
laravel框架常用目录路径

laravel框架常用目录路径 app_path()app_path函数返回app目录的绝对路径:$path = app_path();你还可以使用app_path函数为相对于app目录的给定文件生成绝对路径:$path = app_p...

高处胜寒
19分钟前
0
0
记一次winserver2003系统,https无法访问,内存占用持续增加,解决办法

先交代一下环境: win server2003系统,系统装在hyper-v虚拟机里 大概2016年底的镜像,距离今天两年左右 病症:大概9月10号左右用这个镜像还可以访问https,但是今天用这个镜像新装的系统,就...

阳阳露
34分钟前
3
0
Vue学习资料

一直以为Vue是依赖nodejs的。 作为前端也可以耦合性就很低了。 //npm包管理器 进行管理npm install vue//初始化一个项目vue init//本地调试npm run dev//编译完成 ...

大灰狼wow
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部