转自:http://blog.csdn.net/itolfn/article/details/7412364

一:继承中的指针问题。

1. 指向基类的指针可以指向派生类对象,当基类指针指向派生类对象时,这种指针只能访问派生对象从基类继承



而来的那些成员,不能访问子类特有的元素 ,除非应用强类型转换,例如有基类B和从B派生的子类D,则B



*p;D  dd; p=ⅆ是可以的,指针p只能访问从基类派生而来的成员,不能访问派生类D特有的成员.因为基类不



知道派生类中的这些成员。

2. 不能使派生类指针指向基类对象 .

3. 如果派生类中覆盖了基类中的成员变量或函数,则当声明一个基类指针指向派生类对象时,这个基类指针只能



访问基类中的成员变量或函数。例如:基类B和派生类D都定义了函数f,则B *p; D m; p=&m; m.f()将调用基类中



的函数f()而不会调用派生类中的函数f()。

4. 如果基类指针指向派生类对象,则当对其进行增减运算时,它将指向它所认为的基类的下一个对象,而不会指



向派生类的下一个对象,因此,应该认为对这种指针进行的增减操作是无效的.

二:虚函数

1. 为什么要使用虚函数:正如上面第1 和3 点所讲的,当声明一个基类指针指向派生类对象时,这个基类指针只



能访问基类中的成员函数,不能访问派生类中 特有的成员变量或函数 。如果使用虚函数就能使这个指向派生类对



象的基类指针访问派生类中的成员函数,而不是基类中的成员函数,基于这一点派生类中的这个成员函数就必须和



基类中的虚函数的形式完全相同,不然基类指针就找不到派生类中的这个成员函数。使用虚函数就实现了一个接口



多种方法。

2. 注意不能把成员变量声明为虚有的,也就是说virtual关见字不能用在成员变量前面。

3. 正如上面所介绍的,一般应使用基类指针来调用虚函数,如果用点运算符来调用虚函数就失去了它的意义.

4. 如果基类含有虚函数则当声明了一个基类的指针时 ,当基类指针指向不同的派生类时,它就会调用相应派生



类中定义的虚函数版本.这种调用方法是在运行时 决定的 ,例如在类B中声明了虚函数,C,D,E 都从B继承而



来且都实现了自已的虚函数版本,那么当定义了一个B类的指针P时,当P指向子类C时就会调用子类C中定义的



虚函数,当

P指向子类D时就会调用子类D中定义的虚函数 ,当P指向子类E时就会调用子类E中定义的虚函数 .

5. 虚函数须在基类中用virtual 关见字声明也可以在基类中定义虚函数,并在一个或多个 子类中重新定义 .重



定义虚函数时不需再使用virtual关见字,当然也可以继续标明virtual关见字,以便程序更好理解。

6. 包括虚函数的类被称为多态类.C++使用虚函数支持多态性.

7. 在子类中重定义 虚函数时 ,虚函数必须有与基类虚函数的声明完全相同的参数类型和数量,这和重载是不同



的.如果不相同,则是函数重载,就失去了虚函数的本质.

8. 虚函数不能是声明它的类的友元函数,必须是声明它的类的成员函数,不过虚函数可以是另一个类的友元.

9. 一旦将函数声明为虚函数,则不管它通过多少层继承,它都是虚函数,例如D和B继承,而E又从D继承,那



么在B中声明的虚函数,在类E中仍然是虚函数.

10.隐藏虚函数:如果基类定义了一个 虚函数 ,但派生类中却定义了一个虚函数的重载板本 ,则派生类的这个



版本就会把基类的虚函数隐藏掉,当使用基类指针调用该函数时只能调用基类的虚函数 ,而不能调用派生类的重



载版本,当用派生类的对象调用基类的 虚函数时就会出现错误了 ,因为基类的虚函数被派生类的重载版本隐藏了





11.带默认形参的虚函数:当基类的虚函数带有默认形参时,则派生类中对基类 虚函数的重定义也必须有相同数



量的形参,但形参可以有默认值也可以没有,如果派生类中的 形参数量和基类中的不一样多 ,则是对基类的虚函



数的重载 。

对虚函数的重定义也就意味着,当用指向派生类的基类指针调用该虚函数时就会调用基类中的虚函数版本。比如基

类定义virtual void f(int i=1, int j=2){}则派生类中必须定义带有两个形参的函数f才是对基类虚函数f的重定



义, 不然就是函数f的重载版本,比如派生类中定义的void f(),void f(int i),void f(int i=2)都是对函数f



的重载,不是对f的重定义。而void f(int i, int j),void f( int i, int j=3),void f(int i=4, int j=5)都



是对虚函数f的重定义。

12.如果虚函数形参有默认值,那么派生类中的虚数的形参不论有无默认值,当用指针调用派生类中的虚函数时就



会被基类的默认值覆盖,即派生类的默认值不起作用 。但用派生类的对象调用该函数时,就不会出现这种情况 。

13.当用指向派生类的基类指针调用虚函数时是以基类中的虚函数的形参为标准的,也就是只要调用的形式符合基



类中定义的虚函数的标准就行了。比如基类中定义virtual void f(int i=1,int j=2){}派生类中重定义为void f



(int i, int j=3){}这时如果用派生类的对象调用这个派生类中的 虚函数 f 时必须至少要有一个实参,但是用指



向派生类的基类指针调用该虚函数时就可以不用任何形参就能调用派生类中的这个函数f, 比如语句p->f()就会调



用派生类中的 虚函数版本 。当用指向派生类的基类指针调用虚函数时是以基类中的虚函数的形参为标准的,也就



是只要调用的 形式符合基类中定义的虚函数的标准就行了。

14.析构函数可以是虚函数,但构造函数不能.

15.纯虚函数声明形式为 virtual 类型 函数名(参数列表)=0;注意后面的等于0;

16.如果类至少有一个纯虚函数,则这个类就是抽象的。

17.如果基类只是声明虚函数而不定义虚函数则此虚函数是纯虚函数 . 任何派生类都必须实现纯虚函数的自已的



版本. 如果不实现纯虚函数那么该类也是抽象类。

18.抽象类不能有对象,抽象类只能用作其它类的基类,因为抽象类中的一个或多个函数没有定义,所以不能用抽



象类声明对象,

19.仍然可以用抽象类声明一个指针,这个指针指向派生类对象.

20.如果派生类中未定义虚函数 ,则会使用基类中定义的函数.

21.虚函数虚拟特性是以层次结构的方式来继承的,例如C从B派生而且C中重定义了B中的虚函数,而D又从C



派生且未重定义B中的虚函数,这时声明一个基类指针P,当P指向类D,并调用D中的虚函数时,由于D中未重



定义虚函数他会调用基类中的虚函数版本,这时他会调用类C中的虚函数而不是类B中的虚函数,因为类C比类B



更接近于类D.

#include <iostream>



using namespace std;

class A

{

    public:

    int b;  

        //virtual int b;  //错误,不能把成员变量声明为虚有的

    virtual void f()

    {

        cout<<"继续"<<endl;

    }

    virtual void h(int i=1,int j=2)

    {

        cout<<"继续H"<<endl;

    }

    ~A(){

        cout<<"析构A"<<endl;

    }

};

class B:public A

{

    public:

    int b;

    void f(int i)//重载虚函数f

    {

        cout<<"paif()"<<endl;

    }

    void f(){//在派生类中重定义虚函数f

        cout<<"paixu"<<endl;

    }

    void h(){ //重载虚函数h的版本。注意这里不是对基类虚函数的重定义。

        int b;

        b=5;

        cout<<"B的"<<b<<endl;

    }

    void h(int i,int j=3){

        int b;

        b=j;

        cout<<"paixuH"<<b<<endl;

    }//当基类中的虚函数有默认形参时,派生类中重定义基类中的虚函数的版本必须有相同数量的形参,

     //形参可以有默认值,也可以没有。如果形参数量不一样多则是对虚函数的重载。

    ~B(){

        cout<<"析构B"<<endl;

    }

};

int main(){

    B m;

    A *p=&m;

        //p->b=3/错误,指向派生类的基类指针不能调用派生类中的成员,只能调用基类中的成员,

        //除非该成员是虚函数

    p->f();W//调用派生类中的函数f

//p->f(4);错误,注意这里不是在调用派生类中带一个形参的f函数,因为带一个参数的f函数不是虚函数,

//用指向派生类的基类指针时不会调用派生类中的函数,除非这个函数是虚函数。这里基类中没有定义这种        //带一个形参的f函数,所以这时会出现错误。

p->A::f(); W//调用基类的虚函数f,可以用作用域运算符使用指向派生类的基类指针调用基类的虚函数

p->h();//调用派生类中的虚函数版本h,用指向派生类的基类指针调用虚函数时派生类中的虚函数的默认值在这里不起作用。虽然派生类中的虚函数需要一个参数,

//但这里不给参数仍是调用的派生类的带两个参数的虚函数h,而不是调用派生类中的不带参数的h函数

m.h(); //调用派生类中不带参数的h函数,如果要用对象调用派生类中带两个形参的h函数,在本例中必须使用一个实参值。

    m.h(1);//调用派生类中带两个形参的h函数,用对象调用派生类中的虚函数时函数的默认值不受基类虚函数默认值的影响

    m.A::h(1);// 调用基类中的虚函数h.

}

<转>C++继承中虚函数的使用的更多相关文章

  1. C++ 在继承中虚函数、纯虚函数、普通函数,三者的区别

    1.虚函数(impure virtual) C++的虚函数主要作用是“运行时多态”,父类中提供虚函数的实现,为子类提供默认的函数实现. 子类可以重写父类的虚函数实现子类的特殊化. 如下就是一个父类中的 ...

  2. c++中虚函数

    虽然很难找到一本不讨论多态性的C++书籍或杂志,但是,大多数这类讨论使多态性和C++虚函数的使用看起来很难.我打算在这篇文章中通过从几个方面和结合一些例子使读者理解在C++中的虚函数实现技术.说明一点 ...

  3. C++ Pirmer : 第十五章 : 面向对象程序设计之基类和派生的定义、类型转换与继承与虚函数

    基类和派生类的定义以及虚函数 基类Quote的定义: classs Quote { public: Quote() = default; Quote(cosnt std::string& bo ...

  4. C++中虚函数的作用浅析

    虚函数联系到多态,多态联系到继承.所以本文中都是在继承层次上做文章.没了继承,什么都没得谈. 下面是对C++的虚函数这玩意儿的理解. 一, 什么是虚函数(如果不知道虚函数为何物,但有急切的想知道,那你 ...

  5. C++中虚函数的作用是什么?它应该怎么用呢?(转)

    虚函数联系到多态,多态联系到继承.所以本文中都是在继承层次上做文章.没了继承,什么都没得谈. 下面是对C++的虚函数这玩意儿的理解. 一, 什么是虚函数(如果不知道虚函数为何物,但有急切的想知道,那你 ...

  6. C++中虚函数功能的实现机制

    要理解C++中虚函数是如何工作的,需要回答四个问题. 1.  什么是虚函数. 虚函数由于必须是在类中声明的函数,因此又称为虚方法.所有以virtual修饰符开始的成员函数都成为虚方法.此时注意是vir ...

  7. 从零开始学C++之虚继承和虚函数对C++对象内存模型造成的影响

    首先重新回顾一下关于类/对象大小的计算原则: 类大小计算遵循结构体对齐原则 第一个数据成员放在offset为0的位置 其它成员对齐至min(sizeof(member),#pragma pack(n) ...

  8. c++虚继承与虚函数

    学习继承与多态时看到这两个概念,记录整理. 虚继承与虚函数都是用virtual关键字实现,虚继承为了防止多重继承,而虚函数为了实现多态. 是几个例子. 虚继承: class A{}; class B: ...

  9. C++多重继承分析——《虚继承实现原理(虚继承和虚函数)》

    博客转载:https://blog.csdn.net/longlovefilm/article/details/80558879 一.虚继承和虚函数概念区分 虚继承和虚函数是完全无相关的两个概念. 虚 ...

随机推荐

  1. Go语言核心36讲(Go语言实战与应用八)--学习笔记

    30 | 原子操作(下) 我们接着上一篇文章的内容继续聊,上一篇我们提到了,sync/atomic包中的函数可以做的原子操作有:加法(add).比较并交换(compare and swap,简称 CA ...

  2. 生产服务GC调优实践基本流程总结

    Photo by Pixabay from Pexels 本文作者:夜色微光 - 博客园 (cnblogs.com) 前言 对Java虚拟机进行性能调优是一个非常宽泛的话题,在实践上也是非常棘手的过程 ...

  3. [bzoj5415]归程

    首先肯定要预处理出每一个点到1的最短路(别写spfa) 然后以海拔为边权,建一棵kruskal重构树 用倍增找到vi最后一个小于pi的祖先,然后在子树中取min(预处理) 1 #include< ...

  4. 国内首家!腾讯云正式成为 FinOps 基金会顶级会员

    11月24日,腾讯云正式宣布加入FinOps基金会,作为国内首家FinOps基金会顶级会员,腾讯云将联合FinOps基金会,全面推进对FinOps标准和最佳实践的贡献,为企业提供云财务管理的最佳解决方 ...

  5. 数值最优化:一阶和二阶优化算法(Pytorch实现)

    1 最优化概论 (1) 最优化的目标 最优化问题指的是找出实数函数的极大值或极小值,该函数称为目标函数.由于定位\(f(x)\)的极大值与找出\(-f(x)\)的极小值等价,在推导计算方式时仅考虑最小 ...

  6. AC 自动机学习笔记

    虽然 NOIp 原地爆炸了,目前进入 AFO 状态,但感觉省选还是要冲一把,所以现在又来开始颓字符串辣 首先先复习一个很早很早就学过但忘记的算法--自动 AC AC自动机. AC 自动机能够在 \(\ ...

  7. R语言与医学统计图形-【23】ggplot2坐标系转换函数

    ggplot2绘图系统--坐标系转换函数 包括饼图.环状条图.玫瑰图.戒指图.坐标翻转. 笛卡尔坐标系(最常见). ArcGIS地理坐标系(地图). Cartesian坐标系. polar极坐标系. ...

  8. Linux终端命令行的快捷键列表

    tab键:命令.文件名等自动补全功能. Ctrl+a:光标回到命令行首.Ctrl+e:光标回到命令行尾.Ctrl+k:删除光标处到行尾的字符.Ctrl+u:删除整个命令行文本字符.ctrl+y: 粘贴 ...

  9. 一个好用的快速安装lnmp环境包lnmp1-6

    一个好用的快速安装lnmp环境包lnmp1-6 地址:https://lnmp.org/tag/lnmp1-6/

  10. python基础实战

    字符串的互相转换 字典的排序 字典的排序可以直接把,key值或者,values拿出来排序 也可以用dict.items拿出所有的key,value的值再加key=lambda x:x[1] 来排序. ...