zoukankan      html  css  js  c++  java
  • [CPP] 虚函数与纯虚函数

    本文对 C++ 中对虚函数与纯虚函数做一次简单的总结。

    虚函数:通过 virtual 关键字修饰的函数,作用是允许用父类的指针来调用子类的这个函数。虚函数具有函数体,「虚」不代表它是未实现的,相反地,它是必须要有函数体

    纯虚函数:函数未实现(没有函数体)。定义纯虚函数是为了实现一个接口,起到一个规范的作用,规范继承这个类的程序员必须实现这个函数。

    虚函数

    先看一段代码:

    class A
    {
    public:
        virtual void say() { cout << "A" << endl; }
    };
    class B : public A
    {
    public:
        // 此处的 virtual 可有可无
        void say() { cout << "B" << endl; }
    };
    
    int main()
    {
        A *a = new B();
        a->say();
    }
    // Output: B
    

    上述代码展示的是 virtual 的基本用法,A 中定义一个虚函数,B 中重新实现了一遍,这也是所谓的重写(类似于 Java 的 Override)。

    PS:如果函数 A::say() 没有使用 virtual 修饰,那么就叫 重定义 (Redefining)

    上面这种通过 父类指针调用子类函数 的行为,也被叫做动态绑定(Dynamic Binding),或者动态联编(这个就不知道是谁的翻译,无语子)。动态绑定的含义是:一个类函数的调用并不是在编译时刻被确定的,而是在运行时刻被确定的。

    至于怎么理解「动态」一词呢?

    参考文章:https://www.cnblogs.com/lizhenghn/p/3657717.html

    4 个相关概念:

    • 静态类型:对象在声明时采用的类型,在编译期既已确定;
    • 动态类型:通常是指一个指针或引用目前所指对象的类型,是在运行期决定的;
    • 静态绑定:绑定的是静态类型,所对应的函数或属性依赖于对象的静态类型,发生在编译期;
    • 动态绑定:绑定的是动态类型,所对应的函数或属性依赖于对象的动态类型,发生在运行期;
    int main()
    {
        A *a = nullptr;    // a 的静态类型为 A*
        a = new A();       // a 的动态类型为 A*
        a->say();
        a = new B();       // a 的动态类型变为 B*
        a->say();
    }
    

    也就是说,由于 父类指针可以指向子类 这个特性,对象指针在运行时可以有不同的动态类型的。

    纯虚函数

    纯虚函数是在基类中声明的虚函数,它在基类中没有定义(即没有函数体),但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加 = 0 :

    class A 
    {
    public:
        virtual void say() = 0;
    };
    

    引入纯虚函数/抽象类的原因是:实现多态。

    具有纯虚函数的类,称为抽象类(Abstract Class),不能实例化。其作用类似于 Java 中的接口,每个子类都必须要实现这个纯虚函数。

    class Animal { public: virtual void whoami() = 0; };
    class Cat : public Animal { public: void whoami() { cout << "I am cat." << endl; } };
    class Dog : public Animal { public: void whoami() { cout << "I am dog." << endl; } };
    

    最后,可以看一下 Java 中 interface 的用法,与之十分类似。

    Animal.java 中定义接口:

    package sin;
    
    public interface Animal {
        public void whoami();
        public boolean canFly();
    }
    

    Cat.java 实现接口中定义的所有方法:

    package sin;
    public class Cat implements Animal {
        public void whoami() {
            System.out.println("I am cat.");
        }
        public boolean canFly() {
            return false;
        }
    }
    
  • 相关阅读:
    (ZOJ 3329) One Person Game (概率DP)
    python爬虫之json数据处理
    1034 Head of a Gang 图的遍历,map使用
    1030 Travel Plan Dijkstra+dfs
    vs C++ scanf 不安全
    1021. Deepest Root DFS 求最长无环路径
    1013. Battle Over Cities 用dfs计算联通分量
    无法解析的外部符号
    PAT DFS,BFS,Dijkstra 题号
    1004 Counting Leaves 对于树的存储方式的回顾
  • 原文地址:https://www.cnblogs.com/sinkinben/p/13775706.html
Copyright © 2011-2022 走看看