C++整理——虚函数的使用

由于在公司内一直是在C语言的开发,大多也是在写业务代码,因此对C++的使用越来越生疏。然而最近在公司玩了一个编码比赛最终折戟让我重新意识到用C++的思想来设计工程的重要性。现在借blog重新梳理一下大学所学。如有疏漏不正之处,敬请指出:)

C++区别于C语言是因为它有三大特性:封装,继承,多态。

封装要求类内高内聚,类间低耦合。设计类无论在哪个工程里都是一个大学问,至今我也还在摸索TAT....

继承和多态就是今天主题,

  • 什么是虚函数

  虚函数是指在基类中用virtual标识符标识出来的函数。该函数与基类中其他的函数不同,如果该基类的派生类中有与合格虚函数重名的函数,那么编译器将自动重载成派生类中的重名函数,实现多态。

  talk is cheap, show u the code:

  

 1 #include <iostream>
 2
 3 using namespace std;
 4
 5 class Base
 6 {
 7 public:
 8     void A() { cout << "Base, A()" << endl; };
 9     virtual void B() { cout << "Base, B()" << endl; };
10 };
11
12 class Derive : public Base
13 {
14 public:
15     void A() { cout << "Derive, A()" << endl; };
16     void B() { cout << "Derive, B()" << endl; };
17 };
18
19
20 int main()
21 {
22     Base ex1;
23     Derive ex2;
24
25         // 用基类的指针指向基类,只能调用基类的方法
26     Base *ptr1 = &ex1;
27
28         // !只有用基类的指针指向派生类才是有意义的
29     Base *ptr2 = &ex2;
30
31         // 用派生类的指针只能调用派生类的方法,没有任何意义
32     Derive *ptr3 = &ex2;
33
34         // 输出基类的A, B
35     ptr1->A();
36     ptr1->B();
37
38         // 输出基类的A和派生类的B
39     ptr2->A();
40     ptr2->B();
41
42     return 0;
43 }
  • 什么是纯虚函数

  纯虚函数是指在基类中没有具体实现的虚函数,在C++语法中也就表现成 :

   1 virtual void function() = 0;

这一类的函数由于在基类中没有实现,对于派生类而言就相当于Java中的一个接口函数,因此派生类必须要实现它。同时,有纯虚函数的基类是不能被创建实例的。对于一个工程的设计者而言,这是一个很好的设计。比如现在我有一个基类Career,我只想让派生类Teacher,Doctor等等去实现这个基类里的function而不想Career被实例化,那么我就可以在Career这个类里加入纯虚函数,将其变成一个接口类,便于工程的管理。

  • 什么是虚基类

  虚基类不是有虚函数的基类!

  虚基类不是有虚函数的基类!

  虚基类不是有虚函数的基类!

  重要的事情说三遍!

  由于C++支持多重继承,因此在父类的父类相同时,就很容易发生冲突,产生二义性。因此引入了虚基类的概念。

  我们来看一个经典的菱形继承的问题:

  

1 class B : public A;
2 class C : public A;
3 class D : public B, public C;

  这种场景下,由于D继承的B,C有着相同的父类,因此如果我们声明D的话,D的内存分配中将会有两份A成员的拷贝,分别是D->B->A和D->C->A。A的访问不明确,将无法编译。

  因此,采用虚基类的声明方式:

1 class B : virtual public A;
2 class C : virtual public A;
3 class D : public B, public C;

  在这种声明方式下,D的内存分配中将只会有一份A成员的拷贝,那么具体是通过D->B->A的路径还是D->C->A的路径访问A呢?答案是,都不通过。在这种继承方式下,必须由派生类(D)对直接基类(B,C)和间接基类(A)直接赋值。在这种情况下,只会执行最终派生类对虚基类的赋值,B和C构造函数中初始化列表里对A的赋值都不会执行。

最后,虚基类通过三个重要的函数初始化原则保证无二义性:

  (1)虚基类的构造函数在非虚基类的构造函数前调用

  (2)若同一层次调用了多个虚基类,那么他们的调用顺序按声明的顺序来

  (3)若虚基类由非虚基类派生而来,那么先调用基类的构造函数,再调用派生类的构造函数。

  牢记牢记!~ 

时间: 10-22

C++整理——虚函数的使用的相关文章

【整理】C++虚函数及其继承、虚继承类大小

参考文章: http://blog.chinaunix.net/uid-25132162-id-1564955.html http://blog.csdn.net/haoel/article/details/1948051/ 一.虚函数与继承 1.空类,空类单继承,空类多继承的sizeof #include <iostream> using namespace std; class Base1 { }; class Base2 { }; class Derived1:public Base1

MFC浅析(7) CWnd类虚函数的调用时机、缺省实现

CWnd类虚函数的调用时机.缺省实现 FMD(http://www.fmdstudio.net) 1. Create 2. PreCreateWindow 3. PreSubclassWindow 4. PreTranslateMessage 5. WindowProc 6. OnCommand 7. OnNotify 8. OnChildNotify 9. DefWindowProc 10. DestroyWindow 11. PostNcDestroy CWnd作为MFC中最基本的与窗口打交

c++析构函数为什么要为虚函数

注:本文内容来源于zhice163博文,感谢作者的整理. 1.为什么基类的析构函数是虚函数? 在实现多态时,当用基类操作派生类,在析构时防止只析构基类而不析构派生类的状况发生. 下面转自网络:源地址 http://blog.sina.com.cn/s/blog_7c773cc50100y9hz.html a.第一段代码 #include<iostream> using namespace std; class ClxBase{ public: ClxBase() {}; ~ClxBase()

虚函数、纯虚函数、抽象类、接口 (Java_C++_C#)

在OOP编程语言中,多态是很重要的OOP思想.而多态的语法支持离不开虚函数.每次都把什么虚函数,抽象类搞混,这次好好整理下! -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

【转】C++析构函数为什么要为虚函数

注:本文内容来源于zhice163博文,感谢作者的整理. 1.为什么基类的析构函数是虚函数? 在实现多态时,当用基类操作派生类,在析构时防止只析构基类而不析构派生类的状况发生. 下面转自网络:源地址 http://blog.sina.com.cn/s/blog_7c773cc50100y9hz.html a.第一段代码 #include<iostream> using namespace std; class ClxBase{ public: ClxBase() {}; ~ClxBase()

c++特别要点:多态性与虚函数

本来是准备在工厂模式中顺便整理.但粗略浏览了,内容还是很多,需要单独开一篇. 一.什么是多态性? 多态性可以概括为“一个接口,多种方法”. 多态与非多态的区别在于“成员函数调用地址的早绑定和晚绑定”.“早绑定”在编译期就可以确定函数的调用地址,是静态的:“晚绑定”在运行时才能确定函数的调用地址,是动态的. 多态的作用是什么呢?在面向对象的编程中,“封装”使得代码模块化:“继承”可以扩展以存在的代码:“多态”使得接口重用. 二.多态性的c++实现:虚函数 声明基类的指针,该指针指向子类的对象.调用

c++ 内存分配 虚函数实现多态等

看到了很好的解释,先mark下,有空整理. 虚函数实现多态与多重继承乌索普的回答 很有收获,毕竟我觉得多态才是面向对象的灵魂. 这样的设计也让人得以理解为什么虚函数会像成员变量一样与对象绑定. C++成员函数在内存中的存储方式 原文地址:https://www.cnblogs.com/zsl96/p/8732662.html

&lt;C++&gt; 类(3):初始化列表 常函数和常量对象 虚函数与多态(包括纯虚函数)

一.初始化列表(初始化列表中必须有的两个内容) 1.类中const的成员变量: ①特点:不能修改 必须初始化 在构造函数后面加冒号 格式为:":变量名(值)" 也就是说 常量必须在初始化列表中初始化 ②执行顺序:构造函数先执行初始化列表 然后执行函数中的内容 1 #include<iostream> 2 using namespace std; 3 4 class CPerson 5 { 6 public: 7 const int a; 8 public: 9 CPerso

C++ 虚函数和虚继承浅析

本文针对C++里的虚函数,虚继承表现和原理进行一些简单分析,有希望对大家学习C++有所帮助.下面都是以VC2008编译器对这两种机制内部实现为例. 虚函数 以下是百度百科对于虚函数的解释: 定义:在某基类中声明为 virtual 并在一个或多个派生类中被重新定 义的成员函数[1] 语法:virtual 函数返回类型 函数名(参数表) { 函数体 } 用途:实现多态性,通过指向派生类的基类指针,访问派生类中同名覆盖成员函数 函数声明和定义和普通的类成员函数一样,只是在返回值之前加入了关键字"vir