参考:http://www.weixueyuan.net/view/6371.html

总结:

  virtual关键字仅用于函数声明,如果函数是在类外定义,则不需要再加上virtual关键字了。

  在C++中只有类中的成员函数能被声明为虚函数,而对于顶层函数则不能声明为虚函数。  

  声明虚函数是为了构成多态。

  实际上我们只需要将基类中的display函数通过virtual关键字声明为虚函数,之后即使在派生类中display函数声明时未加上virtual关键字,它在所有的派生类中都将自动成为虚函数。

  和普通的成员函数一样,虚成员函数同样可以被继承。

在上一节中已经提到了虚函数的声明方法了,就是在函数返回类型前加上virtual关键字。virtual关键字仅用于函数声明,如果函数是在类外定义,则不需要再加上virtual关键字了,在C++中只有类中的成员函数能被声明为虚函数,而对于顶层函数则不能声明为虚函数,原因很简单,声明虚函数是为了构成多态,而构成多态的第一个条件就是需要继承关系,顶层函数很明显是不具有继承关系的,因此也就不能被声明为虚函数了。

例1:

#include<iostream>
using namespace std; class base
{
public:
virtual void display();
}; class derived: public base
{
public:
virtual void display(); }; void base::display()
{
cout<<"I'm base class!"<<endl;
} void derived::display()
{
cout<<"I'm derived class!"<<endl;
} int main()
{
base * p = new base;
p->display();
delete p;
p = new derived;
p->display();
delete p;
return ;
}
在本例中,我们将两个类中的display函数在类内部声明,类外部定义,当然这么修改并不会改变程序的运行结果。在本例中我们需要注意的是在类内声明时display函数通过在返回类型前添加了virtual关键字而被声明为了虚函数,而在类外定义时,display函数的返回类型前并未添加virtual关键字。 另外在例1中,我们在基类和派生类中的display函数声明时都加上了virtual关键字,以表示将其声明为虚函数,而实际上这是不需要的,我们只需要将基类中的display函数通过virtual关键字声明为虚函数,之后即使在派生类中display函数声明时未加上virtual关键字,但它在所有的派生类中都将自动成为虚函数。 例2:
#include<iostream>
using namespace std; class base
{
public:
virtual void display();
}; class derived: public base
{
public:
void display(); }; void base::display()
{
cout<<"I'm base class!"<<endl;
} void derived::display()
{
cout<<"I'm derived class!"<<endl;
} int main()
{
base * p = new base;
p->display();
delete p;
p = new derived;
p->display();
delete p;
return ;
}

在本例中,我们将例1中派生类的display成员函数声明时所用的virtual关键字去掉,编译并运行程序,结果显示程序运行结果仍然保持不变。

和普通的成员函数一样,虚成员函数同样可以被继承。

例3:

#include<iostream>
using namespace std; class base
{
public:
virtual void hello(){cout<<"Hello!"<<endl;}
}; class derived: public base
{
//......
}; int main()
{
base * p = new base;
p->hello();
delete p;
p = new derived;
p->hello();
delete p;
derived d;
d.hello();
return ;
}

在本例中,派生类derived中无新增的成员变量或成员函数,它是base类的派生类。我们直接来看主函数。在主函数中依然是定义一个base类类型的指针,然后先后指向基类和派生类的对象。在此例中,因为派生类中并不存在与基类hello函数具有相同函数名的虚函数(继承过来的hello函数与基类中的hello函数并未构成遮蔽关系),因此并未构成多态,自始至终都是调用的都是基类的hello函数。之后又定义了一个派生类对象d,这个对象调用hello函数,当然则个hello同样是继承自基类base中的hello函数了。从这个程序很明显可以看出虚函数是具有继承特性的,这一点它与普通函数一般无二。

 

4.2 C++虚成员函数的更多相关文章

  1. 4.6 C++抽象基类和纯虚成员函数

    参考:http://www.weixueyuan.net/view/6376.html 总结: 在C++中,可以通过抽象基类来实现公共接口 纯虚成员函数没有函数体,只有函数声明,在纯虚函数声明结尾加上 ...

  2. 深入理解类成员函数的调用规则(理解成员函数的内存为什么不会反映在sizeof运算符上、类的静态绑定与动态绑定、虚函数表)

    本文转载自:http://blog.51cto.com/9291927/2148695 总结: 一.成员函数的内存为什么不会反映在sizeof运算符上?             成员函数可以被看作是类 ...

  3. 在成员函数中调用虚函数(关于多态的注意事项)------新标准c++程序设计

    类的成员函数之间可以互相调用.在成员函数(静态成员函数.构造函数和析构函数除外)中调用其他虚成员函数的语句是多态的.例如: #include<iostream> using namespa ...

  4. 从汇编看c++中成员函数指针(一)

    下面先来看c++的源码: #include <cstdio> using namespace std; class X { public: int get1() { ; } virtual ...

  5. C++调用一个成员函数的需求this指针的情况

    1.虚成员函数,因为需要this展望虚表指针的指针 2.在数据成员的操作部件的功能 #include "stdafx.h" #include <iostream> #i ...

  6. C++虚成员函数表vtable

    介绍一下多态是如何实现的,关于如何实现多态,对于程序设计人员来说即使不知道也是完全没有关系的,但是对于加深对多态的理解具有重要意义,故而在此节中稍微阐述一下多态的实现机制. 在C++中通过虚成员函数表 ...

  7. 为什么NULL指针也能访问成员函数?(但不能访问成员变量)

    查看更加详细的解析请参考这篇文章:http://blog.51cto.com/9291927/2148695 看一个静态绑定的例子: 1 #include <iostream> 2 3 u ...

  8. 4.3 C++虚成员函数表vtable

    参考:http://www.weixueyuan.net/view/6372.html 总结: 在C++中通过虚成员函数表vtable实现多态,虚函数表中存储的是类中虚函数的入口地址. 使用多态会降低 ...

  9. C++成员函数指针的应用

     C++中,成员指针是最为复杂的语法结构.但在事件驱动和多线程应用中被广泛用于调用回叫函数.在多线程应用中,每个线程都通过指向成员函数的指针来调用该函数.在这样的应用中,如果不用成员指针,编程是非常困 ...

随机推荐

  1. 雷林鹏分享:XML 编码

    XML 编码 XML 文档可以包含非 ASCII 字符,比如挪威语 æ ø å,或者法语 ê è é. 为了避免错误,需要规定 XML 编码,或者将 XML 文件存为 Unicode. XML 编码错 ...

  2. 2 爬虫 requests模块

    requests模块 Requests是用python语言基于urllib编写的,采用的是Apache2 Licensed开源协议的HTTP库,Requests它会比urllib更加方便,reques ...

  3. docker 基本操作

    # 常用命令   docker run 镜像   docker images 查看所有镜像   docke ps  查看运行中的容器 docker ps -a 列出所有容器     docker st ...

  4. 2-sat学习笔记

    前后缀建图 例:要求n个变量满足至多有1个为true. 暴力:一个点的true向其它n-1个点的false连边,复杂度O(n^2). 正解:prei表示前i个点是否有真. prei的true向prei ...

  5. git 提交代码场景

    1.首次提交代码到master git init git add . git commit -m '' git remote add origin +address git push -u origi ...

  6. 为什么一刷新页面session没了

    最常见的的原因: session_start(); 没有放在文件最上面……

  7. python基础之正则表达式 re模块

    内容梗概: 1. 正则表达式 2. re模块的使⽤ 3. 一堆练习正则表达式是对字符串串操作的一种逻辑公式. 我们一般使用正则表达式对字符串进行匹配和过滤.使用正则的优缺点: 优点: 灵活,功能性强, ...

  8. IntelliJ Idea设置单击打开文件或者双击打开文件、自动定位文件所在的位置

  9. 【其他】【Restful】【1】简单了解Restful概念

    内容: REST是一种设计风格,不是一种标准,是一种思想.符合REST原则的架构方式即可称为RESTful. 在Restful之前的操作:http://127.0.0.1/user/query/1 G ...

  10. 【JS】【1】JavaScript屏蔽Backspace键(避免点击后页面产生回退)

    前言: 1,参考资料:JavaScript屏蔽Backspace键 - 孤傲苍狼 - 博客园(http://www.cnblogs.com/xdp-gacl/p/3785806.html) 2,参考的 ...