1.  
  2. #include <iostream>
  3. #include<string>
  4. #include<vector>
  5. using namespace std;
  6.  
  7. class A
  8. {
  9. public:
  10. void print()
  11. {
  12. cout<<"This is A"<<endl;
  13. }
  14. };
  15.  
  16. class B:public A
  17. {
  18. public:
  19. void print()
  20. {
  21. cout<<"This is B"<<endl;
  22. }
  23. };
  24.  
  25. int main()
  26. { //为了在以后便于区分,我这段main()代码叫做main1
  27. A a;
  28. B b;
  29. a.print();
  30. b.print();
  31. }
  1. 简单地说,那些被virtual关键字修饰的成员函数,就是虚函数。虚函数的作用,用专业术语来解释就是实现多态性(Polymorphism),多态性是将接口与实现进行分离;用形象的语言来解释就是实现以共同的方法,但因个体差异而采用不同的策略。下面来看一段简单的代码

通过class A和class B的print()这个接口,可以看出这两个class因个体的差异而采用了不同的策略,

输出的结果也是我们预料中的,分别是This is A和This is B。但这是否真正做到了多态性呢?
No,多态还有个关键之处就是一切用指向基类的指针或引用来操作对象。那现在就把main()处的代码改一改。

  1. #include <iostream>
  2. #include<string>
  3. #include<vector>
  4. using namespace std;
  5.  
  6. class A
  7. {
  8. public:
  9. void print()
  10. {
  11. cout<<"This is A"<<endl;
  12. }
  13. };
  14.  
  15. class B:public A
  16. {
  17. public:
  18. void print()
  19. {
  20. cout<<"This is B"<<endl;
  21. }
  22. };
  23.  
  24. int main()
  25. {
  26. A a;
  27. B b;
  28. A* p1=&a;
  29. A* p2=&b;
  30. p1->print();
  31. p2->print();
  32. }
  1. 运行一下看看结果,结果却是两个This is A。问题来了,p2明明指向的是class B的对象但却是调用的class Aprint()函数,这不是我们所期望的结果,那么解决这个问题就需要用到虚函数
  2.  
  1. #include <iostream>
  2. #include<string>
  3. #include<vector>
  4. using namespace std;
  5.  
  6. class A
  7. {
  8. public:
  9. virtual void print()
  10. {
  11. cout<<"This is A"<<endl;
  12. }
  13. };
  14.  
  15. class B:public A
  16. {
  17. public:
  18. void print()
  19. {
  20. cout<<"This is B"<<endl;
  21. }
  22. };
  23.  
  24. int main()
  25. {
  26. A a;
  27. B b;
  28. a.print();
  29. b.print();
  30. }
  31.  
  32. int main()
  33. { //main2
  34. A a;
  35. B b;
  36. A* p1=&a;
  37. B* p2=&b;
  38. p1->print();
  39. p2->print();
  40. }

毫无疑问,class A的成员函数print()已经成了虚函数,那么class B的print()成了虚函数了吗?回答是Yes,
我们只需在把基类的成员函数设为virtual,其派生类的相应的函数也会自动变为虚函数。
所以,class B的print()也成了虚函数。那么对于在派生类的相应函数前是否需要用virtual关键字修饰,那就是你自己的问题了。
现在重新运行main2的代码,这样输出的结果就是This is A和This is B了。
现在来消化一下,我作个简单的总结,指向基类的指针在操作它的多态类对象时,会根据不同的类对象,
调用其相应的函数,这个函数就是虚函数。

c++中的虚函数是什么东西?的更多相关文章

  1. EC笔记,第二部分:9.不在构造、析构函数中调用虚函数

    9.不在构造.析构函数中调用虚函数 1.在构造函数和析构函数中调用虚函数会产生什么结果呢? #; } 上述程序会产生什么样的输出呢? 你一定会以为会输出: cls2 make cls2 delete ...

  2. 关于在C#中构造函数中调用虚函数的问题

    在C#中如果存在类的继承关系,应避免在构造函数中调用虚函数.这是由于C#的运行机制造成的,原因如下: 新建一个类实例时,C#会先初始化该类(对类变量赋值,并将函数记在函数表中),然后再初始化父类.构造 ...

  3. C++ 构造函数中调用虚函数

    我们知道:C++中的多态使得可以根据对象的真实类型(动态类型)调用不同的虚函数.这种调用都是对象已经构建完成的情况.那如果在构造函数中调用虚函数,会怎么样呢? 有这么一段代码: class A { p ...

  4. 关于C++虚函数的一些东西

    先上概念,C++的多态性:系统在运行时根据对象类型,来确定调用哪个重载的成员函数的能力. 多态性是通过虚函数实现的.成员函数之前加了virtual,即成为虚函数. 有虚成员函数的类,编译器在其每个对象 ...

  5. C++中的虚函数解析[The explanation for virtual function of CPlusPlus]

    1.什么是虚函数?                                                                                            ...

  6. C++箴言:避免构造或析构函数中调用虚函数

    如果你已经从另外一种语言如C#或者Java转向了C++,你会觉得,避免在类的构造函数或者析构函数中调用虚函数这一原则有点违背直觉.但是在C++中,违反这个原则会给你带来难以预料的后果和无尽的烦恼. 正 ...

  7. 读书笔记 effective c++ Item 9 绝不要在构造函数或者析构函数中调用虚函数

    关于构造函数的一个违反直觉的行为 我会以重复标题开始:你不应该在构造或者析构的过程中调用虚函数,因为这些调用的结果会和你想的不一样.如果你同时是一个java或者c#程序员,那么请着重注意这个条款,因为 ...

  8. C#中的虚函数及继承关系

    转载:http://blog.csdn.net/suncherrydream/article/details/8423991 若一个实例方法声明前带有virtual关键字,那么这个方法就是虚方法. 虚 ...

  9. C++进阶--构造函数和析构函数中的虚函数

    //############################################################################ /* 任何时候都不要在构造函数或析构函数中 ...

随机推荐

  1. Arrays.asList基本用法

    目录 说明 基本用法 陷阱 改观 说明 asList 是 java.util.Arrays 类的一个方法 public static <T> List<T> asList(T. ...

  2. 【bzoj1433】[ZJOI2009]假期的宿舍

    按要求连边,跑匈牙利 #include<algorithm> #include<iostream> #include<cstdlib> #include<cs ...

  3. 启用了不安全的HTTP方法解决办法 IBM APPSCAN

    启用了不安全的HTTP方法解决办法  IBM APPSCAN     安全风险:       可能会在Web 服务器上上载.修改或删除Web 页面.脚本和文件. 可能原因:       Web 服务器 ...

  4. O4编译 在 PingCAP 的一些技术挑战

    在 PingCAP 的一些技术挑战 http://www.zenlife.tk/challenge-at-pingcap.md 在 PingCAP 的一些技术挑战 2018-06-02 事务优化 AC ...

  5. Kills all phantomjs instances, disregard of their origin python关闭进程

    Python/Linux quit() does not terminate PhantomJS process · Issue #767 · SeleniumHQ/selenium https:// ...

  6. SpringMvc參数的接受以及serializeArray的使用方法

    需求:从页面提交一个table中的数据到后台,通经常使用于批量改动 把全部的数据到放到 input属性中,设置name定义成为对象的相关属性,使用Jquery的serializeArray这种方法封装 ...

  7. maven常用命令总结

    搞了多年java 似乎还有些命令 混混沌沌 今儿来总结下 mvn -v 查看版本 mvn -compile 编译当前工程 生成target目录的字节码文件以及报告 mvn -package 将当前工程 ...

  8. vue 做登陆页面 ( 登陆成功后去掉注册和登陆按钮 显示用户名)

    1.当登陆成功  显示用户名且去掉登陆和注册按钮 2.data里声明  后  就在登陆的方法里调用啦 下面说一下登陆的方法. 1.登陆的按钮代码在第一张图片里 2.登陆的弹出框 3.方法 ps:另一种 ...

  9. html5--3.1 form元素

    html5--3.1 form元素 学习要点 form元素及其属性 form元素 用来定义一个表单,是建立表单的基础元素,(就类似定义表格的table) 表单的其他元素包含在form元素中,其主要子元 ...

  10. C语言变量声明问题——变量定义一定要放在所有执行语句/语句块的最前面吗?

    报错信息:error C2065: 'salary' : undeclared identifier #include <stdio.h> void main(){ printf(&quo ...