C++ Virtual And Pure Virtual Explained


Virtual

Virtual Function是成员函数,其行为在派生类中被覆盖。与非虚函数不同的是,即使没有关于类的实际类型的编译时信息,也会保留重写的行为。如果派生类使用指针或者对基类的引用进行处理,则对被覆盖的虚函数的调用将调用派生类中定义的行为。

#include <iostream>

struct Base {
    virtual void f() {
        std::cout << "base\n";
    }
};
struct Derived : Base {
    void f() override { // 'override' is optional
        std::cout << "derived\n";
    }
};
int main()
{
    Base b;
    Derived d;
    
    // virtual function call through reference
    Base& br = b; // the type of br is Base&
    Base& dr = d; // the type of dr is Base& as  well
    br.f(); // prints "base"
    dr.f(); // prints "derived"
    
    // virtual function call through pointer
    Base* bp = &b; // the type of bp is Base*
    Base* dp = &d; // the type of dp is Base* as  well
    bp->f(); // prints "base"
    dp->f(); // prints "derived"
    
    // non-virtual function call
    br.Base::f(); // prints "base"
    dr.Base::f(); // prints "base"
}
//输出
base
derived
base
derived
base
base

虚函数使其类成为多态基类,派生类可以覆盖虚函数。 通过基类指针/引用调用的虚函数将在运行时解析。 也就是说,使用对象的动态类型而不是静态类型。静态类型是指不需要考虑表达式的执行期语义,仅分析程序文本而决定的表达式类型。静态类型仅依赖于包含表达式的程序文本的形式,而在程序运行时不会改变。动态类型是由一个左值表达式表示的左值所引用的最终派生对象的类型。 大致可以这么理解:

  • 静态类型:对象在声明时采用的类型,在编译期既已确定。
  • 动态类型:通常是指一个指针或引用目前所指对象的类型,是在运行期决定的。
  • 静态绑定:绑定的是静态类型,所对应的函数或属性依赖于对象的静态类型,发生在编译期。
  • 动态绑定:绑定的是动态类型,所对应的函数或属性依赖于对象的动态类型,发生在运行期。

Pure Virtual

抽象类是定义或继承至少一个最终覆盖纯虚函数的类,一个纯虚函数隐含的使其自己的类被定义为抽象类,抽象类不能被实例化,只能通过派生类来覆盖实现所有继承的纯虚函数,如果派生类不覆盖实现所有的纯虚函数,那么程序编译不通过报错。何为纯虚函数?格式如下: declarator virt-specifier(optional) = 0 eg: virtual func(optional) = 0; =0只能出现在声明标识符之后或者可选标识符(virtual、final)之后,不能出现在成员函数定义中。

#include <iostream>

struct Base {
    virtual int g();
    virtual ~Base() {}
};

struct A : Base {
    // ok, declares three member virtual functions, two of them pure
    virtual int f() = 0;
	//override代表派生类覆盖父类g()方法
    virtual int g() override = 0;
    virtual int h();
    
    // ok, destructor can be pure too
    virtual ~A() = 0;
    
    // error: pure-specifier on a function definition
    virtual int b()=0 {}
};
//输出为
 virtual int b()=0 {} error: initializer on function does not look like a pure-specifier
struct Abstract {
    virtual void f() = 0; // pure virtual
    virtual void g() {}; // non-pure virtual
    ~Abstract() {
        g(); // okay, calls Abstract::g()
        // f(); // undefined behavior!
        Abstract::f(); // okay, non-virtual call
    }
};
 
//definition of the pure virtual function
void Abstract::f() { std::cout << "A::f()\n"; }
 
struct Concrete : Abstract {
    void f() override {
        Abstract::f(); // OK: calls pure virtual function
    }
    void g() override {}
    ~Concrete() {
        g(); // okay, calls Concrete::g()
        f(); // okay, calls Concrete::f()
    }
};

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏测试开发架构之路

C++之类和对象的使用(三)

对象数组 如果构造函数只有一个参数,在定义数组时可以直接在等号后面的花括号内提供。Student stud[3]={90,92,01};//合法 如果构造函数...

3409
来自专栏CSDN技术头条

常见的七种排序算法解析

01 选择排序 实现原理 首先从未排序序列中找到最小的元素,放置到排序序列的起始位置,然后从剩余的未排序序列中继续寻找最小元素,放置到已排序序列的末尾。所以称之...

2058
来自专栏小樱的经验随笔

关于int *a[常量]与int (*a)[常量]的分析与区分(详解)

前言: 小伙伴私信我说,int *a[常量]与int (*a)[常量]这个区分不开,C指针,确实是C中最难的部分,也是学C++,JAVA,包括你以后上岗用的非常...

2693
来自专栏desperate633

LintCode 编辑距离题目分析代码

给出两个单词word1和word2,计算出将word1 转换为word2的最少操作次数。

772
来自专栏idba

理解Python 生成器与迭代器

前一段时间和同事聊到Python技术知识,发现自己对生成器,迭代器傻傻分不清楚,于是乎查文档,找资料,有了此文。

1021
来自专栏WD学习记录

逆波兰表达式

中缀表达式到后缀表达式的转换 要把表达式从中缀表达式的形式转换成用后缀表示法表示的等价表达式,必须了解操作符的优先级和结合性。优先级或者说操作符的强度决定求...

1943
来自专栏尾尾部落

[剑指offer] 数组中重复的数字

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复...

983
来自专栏深度学习思考者

Python学习(二) 正则表达式

Python正则表达式 正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。re 模块使 Python 语言拥有全部的正则表达式功...

2029
来自专栏猿人谷

qsort(),sort()排序函数

一.qsort()函数 功 能: 使用快速排序例程进行排序 头文件:stdlib.h 用 法: void qsort(void *base,int nelem,...

2308
来自专栏IMWeb前端团队

javascript Array.prototype.sort 排序浅谈

每个 Array 的实例都自带sort 函数,本文对sort函数的用法做一些探讨。 基本用法 1.数组元素为字符串的排序: var fruit = ['cher...

2567

扫码关注云+社区

领取腾讯云代金券