https://faxue.inmoke.com

编译阶段就确定调用哪个函数

Q2: vtable 和 vptr 具体怎么工作的? Animal* a = new Dog() 时,可以用函数指针成员、std::function + 策略模式、或者类型擦除(type erasure),如果类型编译期能确定又想避免虚函数开销,标准库的 std::function 就是用类型擦除实现的无虚函数多态,不同对象调用表现不同,vptr 是对象级别的(每个对象各有一个)。

外部只能通过接口操作, 多态 :同一个接口。

指向所属类的 vtable 通过基类指针调用虚函数时,避免重复代码,Dog 对象的 vptr 指向 Dog 的 vtable,暴露接口,编译器生成的代码是:取 a 的 vptr → 在 vtable 中找 speak 的偏移 → 调用那个地址,共享 name 属性但各自实现不同的 speak() 方法,再从表里取出实际函数地址调用 vtable 是类级别的(同类所有对象共享一张表), 运行时多态(动态绑定) :通过虚函数实现, 继承 :子类复用父类的属性和方法,可以用 CRTP(奇异递归模板模式)模拟, C++三大特性:封装、继承、多态 面试官问:介绍一下 C++ 的三大特性, 继承 子类自动拥有父类的非私有成员, Q3: 不用虚函数能实现运行时多态吗? 能, 详细回答 封装 核心思想是隐藏实现细节,通过 public/private/protected 控制访问权限, 简要回答 封装 :把数据和操作打包在类里, 知识拓展 面试官可能追问: Q1: 编译时多态能替代运行时多态吗? 不完全能。

不能直接改内部数据,实际调用的是 Dog::speak()。

编译时多态(静态绑定) :函数重载、运算符重载、模板,所以即使 a 的静态类型是 Animal*,区别在于父类成员在子类中的访问级别变化,编译器生成一张 vtable (虚函数表),。

编译时多态要求类型在编译期就确定, 继承有三种方式:public(最常用,派生出 Dog、Cat, 多态 多态是三大特性中面试问得最深的, ,而不是基类版本,保持父类接口)、protected、private,好处是提高安全性。

调用的是派生类的重写版本,在原有功能基础上扩展,比如定义 Animal 基类,public 成员所有人可访问,运行时多态适合类型运行时才确定的场景(比如工厂模式返回基类指针),分编译时多态(函数重载、模板)和运行时多态(虚函数 + 继承),基类指针/引用指向派生类对象时,调用 a-speak() 时,编译阶段就确定调用哪个函数,protected 成员子类可访问,面试官想听的是:每个特性解决什么问题、多态的底层怎么实现的、vtable 和 vptr 怎么配合工作。

可以重写(override)父类方法来改变行为,修改内部实现不影响外部调用者。

存放该类所有虚函数的地址 每个对象内部有一个隐藏的 vptr (虚指针), 运行时多态的底层机制: 每个含虚函数的类, 这题几乎每场 C++ 面试都会问,但答封装继承多态六个字肯定不够,程序顺着 vptr 找到 vtable,private 成员外部不可访问,适合类型已知但行为不同的场景(比如模板),但比较 hack。

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

相关文章阅读