C++ 虚函数(多态,多重继承,菱形继承)

多态的实现依赖于虚函数。类存在虚函数,则编译器会为每个类创建虚函数表。

虚函数的调用过程:创建基类赋值给基类指针 --> 虚函数表指针 --> 虚函数表(数组) 里面进行查询并调用实际的函数。

基本实现

cpp 复制代码
#include <iostream>

// 基类
class Base {
public:
	// 虚函数1
    virtual void func1() { std::cout << "Base::func1()" << std::endl; }
    // 虚函数2
    virtual void func2() { std::cout << "Base::func2()" << std::endl; }
};

// 派生类 继承
class Derived : public Base {
public:
    // 重写
    void func1() override { std::cout << "Derived::func1()" << std::endl; }
};

int main() {
    Base* ptr = new Derived();


    // 通过基类指针调用虚函数,运行时动态绑定
    ptr->func1();  // 输出: Derived::func1()
    ptr->func2();  // 输出: Base::func2()
    
    delete ptr;
    return 0;
}

多重继承

派生类继承了多个基类,那就存在多个虚函数指针。

cpp 复制代码
#include <iostream>

// 基类A
class BaseA {
public:
    virtual void funcA() { std::cout << "BaseA::funcA()" << std::endl; }
    virtual void common() { std::cout << "BaseA::common()" << std::endl; }
};

// 基类B
class BaseB {
public:
    virtual void funcB() { std::cout << "BaseB::funcB()" << std::endl; }
    virtual void common() { std::cout << "BaseB::common()" << std::endl; }
};

// 派生类:多重继承自BaseA和BaseB
class Derived : public BaseA, public BaseB {
public:
    void funcA() override { std::cout << "Derived::funcA()" << std::endl; }
    void funcB() override { std::cout << "Derived::funcB()" << std::endl; }
    void common() override { std::cout << "Derived::common()" << std::endl; }
};

int main() {
    Derived d;
    
    // 通过不同基类指针调用虚函数
    BaseA* ptrA = &d;
    BaseB* ptrB = &d;
    
    ptrA->funcA();   // 输出: Derived::funcA()
    ptrA->common();  // 输出: Derived::common()
    
    ptrB->funcB();   // 输出: Derived::funcB()
    ptrB->common();  // 输出: Derived::common()
    
    // 直接通过派生类对象调用
    d.funcA();       // 输出: Derived::funcA()
    d.funcB();       // 输出: Derived::funcB()
    d.common();      // 输出: Derived::common()
    
    return 0;
}

菱形继承

继承关系:

A

/

B C

\ /

D

虚基表

当前例子:D里面会有B和C的虚函数表,当调用公共的虚函数时,会进行进行跳转。

cpp 复制代码
#include <iostream>

class A {
public:
    virtual void foo() { std::cout << "A::foo()" << std::endl; }
};

class B : virtual public A {
public:
    void foo() override { std::cout << "B::foo()" << std::endl; }
};

class C : virtual public A {
public:
    void foo() override { std::cout << "C::foo()" << std::endl; }
};

class D : public B, public C {
public:
    void foo() override { std::cout << "D::foo()" << std::endl; }
};

int main() {
    D d;
    A* ptr = &d;
    ptr->foo();  // 输出: D::foo()
    
    return 0;
}
相关推荐
2501_930707784 小时前
使用C#代码在 PowerPoint 中组合或取消组合形状
开发语言·c#
晚烛4 小时前
CANN 调试工具与性能剖析:从日志分析到 NPU 行为追踪的完整调试体系
开发语言·windows·python·深度学习·缓存
惊鸿一博5 小时前
图标加载方式_zeroIcon_是否加前缀mdi
开发语言·前端·javascript
森G5 小时前
TypeScript 基础类型
开发语言·typescript
小poop6 小时前
string 类从入门到深入
c++
huipeng9266 小时前
企业级微服务开发实战(一):项目启动与工程化设计
java·开发语言·spring boot·spring cloud·微服务·云原生·架构
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ6 小时前
java实现excel导入、下载模板方法
java·开发语言·excel
眠りたいです6 小时前
现代C++:C++14中的新语言特性和库特性
c语言·开发语言·c++
叶小鸡7 小时前
Java 篇-项目实战-AI 天机学堂(从 0 到 1)-day1
java·开发语言
浅念-8 小时前
LeetCode 回溯算法题——综合练习
数据结构·c++·算法·leetcode·职场和发展·深度优先·dfs