转自: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. ABP Framework 5.0 RC.1 新特性和变更说明

    .Net 6.0 发布之后,ABP Framework 也在第一时间进行了升级,并在一个多星期后(2021-11-16)发布了 5.0 RC.1 ,新功能和重要变更基本已经确定. 5.0版本新特性 新 ...

  2. [bzoj1735]泥泞的牧场

    考虑木板一定都尽量长,对于每一个污泥,最多只有两种木板会覆盖它(横着和竖的),将这两块木板连边,意味着每一条边两端端点中一定有一个点要被选,即最小点覆盖=最大匹配数. 1 #include<bi ...

  3. [hdu6595]Everything Is Generated In Equal Probability

    计算一对逆序对的贡献,即在n个数期望要删多少步才能删掉其中的两个数,设f(n)表示此时的期望,则有方程$f[n]=3/4+(\sum_{i=2}^{n}f[i]\cdot c(n-2,i-2))/2^ ...

  4. [bzoj4651]网格

    考虑将最上中最左的跳蚤孤立,容易发现他的上面和左面没有跳蚤,因此只需要将他的右边和下边替换掉就可以了答案为-1有两种情况:1.c>=n*m-1;2.c=n*m-2且这两只跳蚤相邻对于其他情况,将 ...

  5. 【PS】证件照修改尺寸

    证件照同时修改尺寸.分辨率.像素 2019-07-14  12:56:25  by冲冲 1. 需求 实现证件照自由切换一寸.小一寸.大一寸.二寸. 2. 步骤 ① 裁剪工具 -- 原始比例 -- 存储 ...

  6. IDEA远程快速部署SpringBoot项目到Docker环境

    一:基础准备 1.首先在linux服务器安装Docker环境,具体安装步骤及Docker使用参考官网或网络资料(这里重点是快速部署项目到Docker环境) 2.配置Docker远程连接端口 1.vim ...

  7. Cannot connect to runtime process

    发生一个或多个错误. 未能启动调试适配器.可以在输出窗口中查看额外的信息. Cannot connect to runtime process, timeout after 10000 ms (rea ...

  8. Codeforces 848C Goodbye Souvenir(CDQ 分治)

    题面传送门 考虑记录每个点的前驱 \(pre_x\),显然答案为 \(\sum\limits_{i=l}^{r} i-pre_i (pre_i \geq l)\) 我们建立一个平面直角坐标系,\(x\ ...

  9. 洛谷 P6788 - 「EZEC-3」四月樱花(整除分块)

    题面传送门 题意: 求 \[\prod\limits_{x=1}^n\prod\limits_{y|x}\frac{y^{d(y)}}{\prod\limits_{z|y}z+1} \pmod{p} ...

  10. 如何根据taxid(或taxname)快速获得taxname(或taxid)?

    目录 需求 实现 需求 我有一个物种taxonomy ID的list,想获得相应的物种名,不要一个个去NCBI Taxonomy官网查.反之根据物种名list查询对应的taxid. 实现 因为之前没怎 ...