【笔记整理】我们仍未知道那天所用的虚函数的原理

来源:互联网 发布:猪八戒局域网考试软件 编辑:程序博客网 时间:2024/05/16 18:15

一、什么是虚函数

c++的一个类中,如果一个函数前用了virtual关键字,那么这就是一个虚函数

一个非常简单的示例

private:    int i;public:    base() : i(0){};    base(int num) : i(num){};    ~base(){};    virtual void printI();//<-这个就是虚函数!!!!!!    void print();};

注:
构造函数不能是虚函数:如果是把存在的派生类地址给基类指针,那么早就构造好了;如果用new,似乎不涉及基类指针,相当于生成一个派生类,之后再把派生类地址给指针。
析构函数建议写成虚函数

二、虚函数有什么用

当你的基类和(多个)派生类中有同名函数时,你可以用虚函数确定调用哪一个类的该名函数。

如果用基类的指针指向派生类(upcasting),这时候调用某一派生类和基类同名函数,会直接调用基类的该函数。
若要调用派生类的该函数,就要把基类中该函数写成虚函数

三、通过具体例子来理解虚函数

如果是虚函数,则√
是否是virtual

当用指针指向派生类时,调用的是哪个函数
调用了谁

所得结果

L1
base : 12
L2
L2 : 21
L2
base : 23

代码
main.cpp

#include<iostream>#include"cbase.h"int main(){    base B(1), *pB;    Level1 Lev1(11,12), *p1;    Level2 Lev2(21,22,23);    pB = &Lev1;    p1 = &Lev2;    //base指向Level1    pB->print();    //base中为virtual,向上到派生类的同名函数、调用L1中的print()    pB->printI();    //指针的类型类中的该函数为非虚函数,直接调用该非虚函数    //Level1指向Level2    p1->print();    p1->printI();    //因为Level1中的两个函数都是虚函数,所以都调用的L2中的同名函数    //base指向Level2    pB = &Lev2;    pB->print();    //从basez中的虚函数一路向上,调用L2的同名函数    pB->printI();    //虽然L1是虚函数,但这是base类的指针    //base中该函数为非虚函数,调用base中函数        return 0;}

cbase.h

////  cbase.h//  classwork////  Created by 陈天乐 on 16/12/22.//  Copyright (c) 2016年 陈天乐. All rights reserved.//#ifndef classwork_cbase_h#define classwork_cbase_hclass base{private:    int i;public:    base() : i(0){};    base(int num) : i(num){};    ~base(){};    void printI();    virtual void print();};class Level1 : public base{private:    int L1;public:    Level1() : L1(0),base(){};    Level1(int a) : L1(a),base(){};    Level1(int a, int b) : L1(a),base(b){};    ~Level1(){};    virtual void printI();    virtual void print();};class Level2 : public Level1{private:    int L2;public:    Level2() : L2(0),Level1(){};    Level2(int a) : L2(a),Level1(){};    Level2(int a, int b) : L2(a),Level1(b){};    Level2(int a, int b, int c) : L2(a), Level1(b,c){};    ~Level2(){};    void printI();    virtual void print();};#endif

cbase.cpp

////  cbase.cpp//  classwork////  Created by 陈天乐 on 16/12/22.//  Copyright (c) 2016年 陈天乐. All rights reserved.//#include "cbase.h"#include<iostream>void base::printI(){    std::cout << "base : " << i << std::endl;}void base::print(){    std::cout << "base" << std::endl;}void Level1::printI(){    std::cout << "L1 : " << L1 << std::endl;}void Level1::print(){    std::cout << "L1" << std::endl;}void Level2::printI(){    std::cout << "L2 : " << L2 << std::endl;}void Level2::print(){    std::cout << "L2" << std::endl;}

四、阅读学习其他博客的理解和总结

  • 关于多态的理解:同一消息(调用函数),不同方法(不同的函数体)
  • C++中运行时的多态性主要是通过虚函数来实现的
  • 虚函数令函数调用与函数体之间的联系在运行时才建立
  • 虚可以理解为,在动态调用的时候,这个函数是隐藏的。要去找最表面的一个。
  • 若在基类中显式声明了虚函数,之后的派生类中的同名函数会自动变成虚函数。
    说明
    知道了这一点后我有一个疑惑:按照这个原理,如果我再增加一个L3层,用L2的指针指向L3并且调用F2,依然会调用L3自己的printI。
    验证了一下没有错误。
    当一个类中存在一个虚函数,这个类的所有子类的同名都自动变为虚函数
    虚函数
    绿色代表,会调用指针的类型的F1
    黄色代表,会调用指针指向的类型的F1
  • 只有公有派生类才能使用基函数(赋值兼容)
  • 虚函数必须是成员函数,不能是友元函数、静态成员函数、内联函数(可能出题)具体为什么(还没深入研究qwq,似乎是虚函数涉及到对象内部)

改错题
virtual void F1() const;

  • 纯虚函数的概念:virtual void F1() = 0;//这就是一个纯虚函数

其中的= 0 只是一个标记。纯虚函数不在实现文件里定义。
纯虚函数不能被调用(那它能做什么??)
拥有纯虚函数的类会变成抽象类
抽象类只能作为基类,不能作为派生类
因为抽象类自己不能生成对象。只有继承了这个抽象类的派生类可以生成对象。
纯虚函数用来规范派生类的行为,提高安全性,可以理解为接口(?我对接口还不是很理解)

纯虚函数的意义,让所有的类对象(主要是派生类对象)都可以执行纯虚函数的动作,但类无法为纯虚函数提供一个合理的缺省实现。所以类纯虚函数的声明就是在告诉子类的设计者,“你必须提供一个纯虚函数的实现,但我不知道你会怎样实现它”。

参考资料:
C++之多态性与虚函数
C++的精髓——虚函数
虚函数和纯虚函数的区别
知乎:c++虚函数的作用是什么?

其他的一些东西

1.
w

2.
使用虚函数能够简化写代码的过程,但是对提高程序运行效率没有帮助
因为虚函数实现的功能你也可以自己实现,但是写起来很麻烦,c++直接帮你写好了虚函数的机制

0 0