干货较多-需要自己深思理解:

C++支持两种多态性:
1.编译时多态性(静态绑定-早绑定)
在程序编译阶段即可以确定下来的多态性
通过使用 重载机制(重载函数)实现

(模板)http://blog.csdn.net/my_business/article/details/12194691

2.运行时多态性(动态绑定-晚绑定)
必须等到程序运行时才能确定的多态性
要通过 虚函数 来实现

http://blog.csdn.net/zp752963831/article/details/46635885

第一个父类中 把某个函数 定义成虚函数 ,那么在他的子类中 无论是否加 virtual 都是 虚函数。

例子:

class Base
{
public:
virtual void fun(int i)
{
OutputDebugString(_T("Base::fun(int i)"));
}
}; class BaseA :public Base
{
public:
virtual void fun(int i)
{
OutputDebugString(_T("BaseA::fun(int i)"));
}
};

其中BaseB 的fun函数 加与不加virtual函数都无所谓,其都是虚函数

但是如果他继续作为基类,并且要用到多态,则其应该加一个virtual

 

虚函数的访问权限:
派生类中所定义的虚函数的访问权限 不会影响对它的晚绑定
(即:只有在第一个父类中定义的public,private或protect才对 虚函数的访问 有控制功能)

晚绑定 和 实例化对象 的 class 中函数的访问权限有关

class base
{
public:
base():strBase(_T("base"))
{
log();
}
virtual void log()
{
MessageBox(::GetTopWindow(NULL), _T("base"), _T("base"), MB_OK);
}
public:
param strBase;
param* pStr;
}; class child : public base
{
public:
child()
{ }
/*child(const child& other)
{
pStr = new param(_T("child2"));
}*/
pritave:
virtual void log()
{
MessageBox(::GetTopWindow(NULL), _T("child"), _T("child"), MB_OK);
}
public: };
int main()
{
  base * pBase = new child();
  pBase->log();//ok
  child* pChild = static_cast<child*> pBase;
  pChild->log();//error
}

在成员函数中调用虚函数:
在一个基类或派生类的虚或非虚成员函数中可以直接调
用该类体系的虚函数或非虚函数

class base
{
public:
base()
{
log();
}
void go()
{
log();
}
virtual void log()
{
MessageBox(::GetTopWindow(NULL), _T("base"), _T("base"), MB_OK);
}
}; class child : public base
{
public:
child()
{ }
void go()
{
log();
}
private:
virtual void log()
{
MessageBox(::GetTopWindow(NULL), _T("child"), _T("child"), MB_OK);
} public: };
int main()
{
base * pBase = new child();
pBase->go();//ok 调用父类的go,内部调用子类的log函数。
child* pChild = static_cast<child*>(pBase);
pChild->go(); //go 内部直接调用自己的
}

在构造/析构函数中调用虚函数:
在构造函数或析构函数中调用虚函数时,采用的是早绑定。
也就是虚函数机制在构造函数中不工作。

class base
{
public:
base()
{
log();
}
void go()
{
log();
}
virtual void log()
{
MessageBox(::GetTopWindow(NULL), _T("base"), _T("base"), MB_OK);
}
}; class child : public base
{
public:
child()
{
log();
}
void go()
{
log();
}
private:
virtual void log()
{
MessageBox(::GetTopWindow(NULL), _T("child"), _T("child"), MB_OK);
}
};
int main()
{
base * pBase = new child();//构造父类时,父类构造调用自己的 // log ,子类构造,则用子类的log函数。
}

虚函数和缺省实参:
运行的函数是派生来的函数,但使用的缺省实参是父类里的缺省实参
即:虚函数的缺省实参不支持晚绑定。

class base
{
public:
base()
{
}
virtual void log(int paramI = )
{
SStringT str = paramI;
OutputDebugString(str);
}
}; class child : public base
{
public:
child()
{
}
virtual void log(int paramI = )
{
SStringT str = paramI;
OutputDebugString(str);
}
};
int main()
{
base * pBase = new child();
pBase->log();// 输出 1
child* pChild = static_cast<child*>(pBase);
pChild->log(); //输出2
}

纯虚函数:
定义:纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。
在基类中实现纯虚函数的方法是在函数原型后加“ =0”:virtual void funtion1()=0
*引入原因:
1)为了方便使用多态特性,我们常常需要在基类中定义虚拟函数。
2)在很多情况下,基类本身生成对象是不合情理的。

3)实现接口

引入了纯虚函数的概念,将函数定义为纯虚函数(方法:virtual ReturnType Function()= 0;),则编译器要
求在派生类中必须予以重载以实现多态性。同时含有纯虚拟函数的类称为抽象类,它不能生成对象。

  

覆盖:
在c++中,派生类继承了基类的全部特征,但有时为了更加准确地描述客观世界的对象,需要对从基类继承来的接口函数进行修改:
这可以通过在派生类中定义一个与基类同名,而返回值,参数类型,顺序或个数都可同可不同的函数,
这样,通过派生类对象调用该同类型的函数时,调用的是派生类中定义的函数。也就是说,
派生类修改了从基类继承来的接口行为,也可称为派生类的函数覆盖了基类中的同名函数。

重载:重载类成员函数与覆盖有点类似:相同的方法(函数名)完成不同的行为

覆盖和重载的 区别:
1.重载是与被重载函数同名,而参数不同(类型、顺序或者数量,至少三者之一不同),返回值可同可不同的另一个函数。
2.重载函数必须在同一个类中或不属于类成员的普通函数之间,不能分布在基类与派生类中。
3.覆盖是,在基类与派生类中出现的标示符同名的情况。

注:
1.虚函数是一组特殊的覆盖函数,同组虚函数间要求函数名、返回值、参数类型、数量、顺序都相同。
通过对象名调用虚函数时,与调用覆盖函数的规则一样-----采用早绑定。
通过对象的指针或引用调用虚函数时采用晚绑定,调用的是指针实际指向,或实际引用的对象对应的类中定义的虚函数

2.如果类外的两个同名函数,或同类中两个同名的成员函数参数相同,但返回值不同,编译器不认为是重载,而认为它们具有二义性,会给出错误提示。
3.如果一组虚函数中,两个虚函数仅返回值不同,但其参数和名字都相同,编译器也认为出错。

三者比较表格:

*=======================================================================================*
|函数名 |返回值 |参数 |绑定时间 |适用范围 |
*---------------+---------------+---------------+-----------------------+---------------*
|虚函数 |同 |同 |晚绑定(指针/引用调用)|基类与派生 |
| | | |早绑定(对象名调用) |类之间 |
*---------------+---------------+---------------+-----------------------+---------------*
|重载函数 |可同可不同 |必须不同 |早绑定 |类外函数或同 |
| | | | |一类中的函数 |
*---------------+---------------+---------------+-----------------------+---------------*
|覆盖函数 |可同可不同 |可同可不同 |早绑定(支配规则) |基类与派生类 |
| | | | |之间 |
*=======================================================================================*

C++之虚函数和多态的更多相关文章

  1. 你好,C++(37)上车的人请买票!6.3.3 用虚函数实现多态

    6.3.3  用虚函数实现多态 在理解了面向对象的继承机制之后,我们知道了在大多数情况下派生类是基类的“一种”,就像“学生”是“人”类中的一种一样.既然“学生”是“人”的一种,那么在使用“人”这个概念 ...

  2. C++虚函数与多态

    C++多态性是通过虚函数来实现的,虚函数允许子类重新定义成员函数,而子类重新定义父类的做法称为覆盖(override),或者称为重写.(这里我觉得要补充,重写的话可以有两种,直接重写成员函数和重写虚函 ...

  3. c++语言虚函数实现多态的原理(更新版)

    自上一个帖子之间跳过了一篇总结性的帖子,之后再发,今天主要研究了c++语言当中虚函数对多态的实现,感叹于c++设计者的精妙绝伦 c++中虚函数表的作用主要是实现了多态的机制.首先先解释一下多态的概念, ...

  4. 从零开始学C++之虚函数与多态(一):虚函数表指针、虚析构函数、object slicing与虚函数

    一.多态 多态性是面向对象程序设计的重要特征之一. 多态性是指发出同样的消息被不同类型的对象接收时有可能导致完全不同的行为. 多态的实现: 函数重载 运算符重载 模板 虚函数 (1).静态绑定与动态绑 ...

  5. 从零开始学C++之虚函数与多态(二):纯虚函数、抽象类、虚析构函数

    一.纯虚函数 虚函数是实现多态性的前提 需要在基类中定义共同的接口 接口要定义为虚函数 如果基类的接口没办法实现怎么办? 如形状类Shape 解决方法 将这些接口定义为纯虚函数 在基类中不能给出有意义 ...

  6. C++中的重载,隐藏,覆盖,虚函数,多态浅析

    直到今日,才发现自己对重载的认识长时间以来都是错误的.幸亏现在得以纠正,真的是恐怖万分,雷人至极.一直以来,我认为重载可以发生在基类和派生类之间,例如: class A { public: void ...

  7. C++虚函数实现多态原理(转载)

    一.前言 C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有"多种形态 ...

  8. C++面向对象编程之虚函数与多态和继承和复合下的构造和析构

    1.对于非虚函数,是不希望派生类对该函数重新定义: 对于virtual函数,在父类已经有默认定义后,并希望子类重新定义它: 对于pure virtual函数,父类没有默认定义,派生类必须要重新定义它: ...

  9. 虚函数&多态

    对于经常被问到的虚函数和多态的问题,发现百度百科回答得十分详细,所以自己在百度百科上的解释进行总结 一.虚函数 (1)虚函数简介:在某基类中声明为virtual并在一个或者多个派生类中被重新定义的成员 ...

随机推荐

  1. 解决iscroll5在手机页面上onclick事件失效

    Iscroll.js使用之后页面上面A标签的onclick事件无效了   解决办法 实例化IScroll的时候把preventDefault设为false,默认为true var myScroll; ...

  2. PhpStorm配置svn时提示需要证书:authentication required的解决方法,总是弹出

    总是弹出下面的框框,每次输入svn账号密码,还是不行. 于是上网查了半天,需要安装和配置SlikSvn.于是就下载安装了. 完了还是不行,就尝试着配置. 上面和下面的加上,svn.exe的地址. 再次 ...

  3. 【Java】需要注意的小细节

    一.==和equals 1.比较两个变量时 a.==可以判断两个变量是否相等,如果两个变量是基本类型变量,而且是数值类型,只要两个变量值相等,返回true. 2.比较两个引用变量 a.==只有两个引用 ...

  4. webpack + react + es6, 并附上自己碰到的一些问题

    最近一直在学react,react的基础部分已经学得差不多了,然而自己并没有做详细的记录,有兴趣的同志可以参考阮一峰老师的教程,个人觉得挺不错的,链接如下:https://github.com/rua ...

  5. [讨论] 这几天来封装Win7用户配置文件丢失的解决方法个人心得

    [讨论] 这几天来封装Win7用户配置文件丢失的解决方法个人心得 prerouting 发表于 2010-5-9 16:50:46 https://www.itsk.com/thread-36634- ...

  6. Oracle安装时OracleMTSRecoveryService找不到

    电脑重做系统之后再安装oracle过程中出现一个问题,说OracleMTSRecoveryService找不到指定的目录文件,卸载重装还是没有改变,挣了半天终于找到怎么更改了,打开注册表编辑器,SYS ...

  7. LOL

    当输入数据一样时,计算结果是一样的,但运行时间的差别很大.在算法正确的前提下,应该选择算法效率高的 嵌入式软件,BSP驱动,通信协议,上层应用软件. 多协议标签交换(MPLS)是一种用于快速数据包交换 ...

  8. 不使用插件实现对WordPress默认编辑器的增强

    四处寻觅无果.无意看了一下wordpress官方的API函数.苍天有眼啊!原来,后台的编辑器可以插入很多增强功能.果断卸载掉CK and SyntaxHighlighter编辑器插件.事实上,Word ...

  9. Java Integer(-128~127)值的==和equals比较产生的思考

    最近在项目中遇到一个问题,两个值相同的Integer型值进行==比较时,发现Integer其中的一些奥秘,顺便也复习一下==和equals的区别,先通过Damo代码解释如下: System.out.p ...

  10. 点击按钮div显示,点击div或者document,div隐藏

    $("button").click(function(event){ event.stopPropagation(); if($("div").is(':hid ...