0

0

C++多态是怎么实现的 虚函数与动态绑定机制

P粉602998670

P粉602998670

发布时间:2025-07-18 11:12:02

|

349人浏览过

|

来源于php中文网

原创

c++++多态性通过虚函数和动态绑定机制实现。1. 虚函数允许子类重写父类的方法,动态绑定在运行时确定调用哪个版本的函数;2. 虚函数表(vtable)是包含虚函数地址的函数指针数组,每个对象通过虚函数指针(vptr)指向其类的vtable,从而在运行时找到实际调用的函数;3. 基类析构函数应声明为虚函数,以确保通过基类指针删除派生类对象时能正确调用派生类和基类的析构函数,避免内存泄漏;4. 纯虚函数没有具体实现,包含纯虚函数的类为抽象类,不能被实例化,只能被继承;5. 动态绑定带来运行时函数地址查找的性能开销,虽比静态绑定慢,但通常可接受,必要时可用静态绑定或模板优化性能。

C++多态是怎么实现的 虚函数与动态绑定机制

C++多态性通过虚函数和动态绑定机制实现。简单来说,虚函数允许子类重写父类的方法,而动态绑定则是在运行时确定调用哪个版本的函数。

C++多态是怎么实现的 虚函数与动态绑定机制

虚函数与动态绑定机制

C++多态是怎么实现的 虚函数与动态绑定机制

虚函数表(Vtable)和虚函数指针(Vptr)

每个包含虚函数的类都会有一个虚函数表(Vtable),它是一个函数指针数组,存储着该类所有虚函数的地址。类的每个对象都会包含一个虚函数指针(Vptr),指向该类的Vtable。当通过指针或引用调用虚函数时,编译器会通过Vptr找到Vtable,然后根据函数在Vtable中的偏移量找到实际要调用的函数地址。

立即学习C++免费学习笔记(深入)”;

这种机制的关键在于,Vtable是在编译时确定的,而Vptr是在运行时确定的。因此,即使在编译时不知道对象的具体类型,也可以在运行时正确地调用相应的虚函数。

C++多态是怎么实现的 虚函数与动态绑定机制

举个例子:

class Animal {
public:
    virtual void makeSound() {
        std::cout << "Generic animal sound" << std::endl;
    }
};

class Dog : public Animal {
public:
    void makeSound() override {
        std::cout << "Woof!" << std::endl;
    }
};

class Cat : public Animal {
public:
    void makeSound() override {
        std::cout << "Meow!" << std::endl;
    }
};

int main() {
    Animal* animal1 = new Animal();
    Animal* animal2 = new Dog();
    Animal* animal3 = new Cat();

    animal1->makeSound(); // 输出 "Generic animal sound"
    animal2->makeSound(); // 输出 "Woof!"
    animal3->makeSound(); // 输出 "Meow!"

    delete animal1;
    delete animal2;
    delete animal3;

    return 0;
}

在这个例子中,Animal 类声明了一个虚函数 makeSound()DogCat 类都重写了这个函数。在 main() 函数中,我们创建了指向 Animal 对象的指针,但实际上它们指向的是 AnimalDogCat 类型的对象。当调用 makeSound() 函数时,由于它是虚函数,所以会根据对象的实际类型来调用相应的函数。这就是动态绑定的体现。

Endel.io
Endel.io

Endel是一款可以创造个性化舒缓声音的应用程序,可帮助您集中注意力、放松身心和入睡。

下载

为什么需要虚析构函数?

如果基类的析构函数不是虚函数,那么通过基类指针删除派生类对象时,只会调用基类的析构函数,而不会调用派生类的析构函数,这会导致内存泄漏。

考虑以下代码:

class Base {
public:
    Base() { std::cout << "Base constructor" << std::endl; }
    ~Base() { std::cout << "Base destructor" << std::endl; }
};

class Derived : public Base {
public:
    Derived() {
        std::cout << "Derived constructor" << std::endl;
        data = new int[10];
    }
    ~Derived() {
        std::cout << "Derived destructor" << std::endl;
        delete[] data;
    }
private:
    int* data;
};

int main() {
    Base* b = new Derived();
    delete b; // 只调用Base的析构函数,导致内存泄漏
    return 0;
}

如果将 Base 类的析构函数声明为虚函数,那么通过基类指针删除派生类对象时,会先调用派生类的析构函数,然后再调用基类的析构函数,从而避免内存泄漏。

class Base {
public:
    Base() { std::cout << "Base constructor" << std::endl; }
    virtual ~Base() { std::cout << "Base destructor" << std::endl; }
};

class Derived : public Base {
public:
    Derived() {
        std::cout << "Derived constructor" << std::endl;
        data = new int[10];
    }
    ~Derived() {
        std::cout << "Derived destructor" << std::endl;
        delete[] data;
    }
private:
    int* data;
};

int main() {
    Base* b = new Derived();
    delete b; // 先调用Derived的析构函数,再调用Base的析构函数
    return 0;
}

纯虚函数和抽象类

纯虚函数是在基类中声明的虚函数,它没有具体的实现。包含纯虚函数的类称为抽象类。抽象类不能被实例化,只能被继承。

class Shape {
public:
    virtual double area() = 0; // 纯虚函数
};

class Circle : public Shape {
public:
    Circle(double r) : radius(r) {}
    double area() override { return 3.14159 * radius * radius; }
private:
    double radius;
};

int main() {
    // Shape s; // 错误:不能实例化抽象类
    Circle c(5);
    std::cout << "Area: " << c.area() << std::endl;
    return 0;
}

在这个例子中,Shape 类是一个抽象类,因为它包含一个纯虚函数 area()Circle 类继承了 Shape 类,并实现了 area() 函数。

动态绑定带来的性能开销

动态绑定需要在运行时查找函数地址,这会带来一定的性能开销。与静态绑定相比,虚函数调用通常会慢一些。然而,这种开销通常是可以接受的,因为动态绑定带来的灵活性和可扩展性往往更重要。在对性能有严格要求的场景下,可以考虑使用静态绑定或模板等技术来避免动态绑定带来的开销。

相关专题

更多
java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

14

2025.11.27

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

14

2025.11.27

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

14

2025.11.27

vlookup函数使用大全
vlookup函数使用大全

本专题整合了vlookup函数相关 教程,阅读专题下面的文章了解更多详细内容。

28

2025.12.30

金山文档相关教程
金山文档相关教程

本专题整合了金山文档相关教程,阅读专题下面的文章了解更多详细操作。

29

2025.12.30

PS反选快捷键
PS反选快捷键

本专题整合了ps反选快捷键介绍,阅读下面的文章找到答案。

25

2025.12.30

表格中一行两行的方法
表格中一行两行的方法

本专题整合了表格中一行两行的相关教程,阅读专题下面的文章了解更多详细内容。

4

2025.12.30

cpu温度过高解决方法大全
cpu温度过高解决方法大全

本专题整合了cpu温度过高相关教程,阅读专题下面的文章了解更多详细内容。

5

2025.12.30

ASCII码介绍
ASCII码介绍

本专题整合了ASCII码相关内容,阅读专题下面的文章了解更多详细内容。

31

2025.12.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Excel 教程
Excel 教程

共162课时 | 10.1万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.0万人学习

NumPy 教程
NumPy 教程

共44课时 | 2.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号