虚函数、纯虚函数、多态

这篇具有很好参考价值的文章主要介绍了虚函数、纯虚函数、多态。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一.虚函数

        在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据所指对象的实际类型来调用相应的函数,如果对象类型是派生类,就调用派生类的函数,如果对象类型是基类,就调用基类的函数。

注意:如果子类没有重写虚函数,那么子类对象仍然有虚指针,虚指针指向的是基类的虚函数表!

  • 虚函数的限制
    • 1.只有类的成员函数才能说明为虚函数
    • 2.静态成员函数不能写为虚函数
    • 3.内联函数不能为虚函数
    • 4.构造函数不能为虚函数
    • 5.析构函数可以写成虚函数

(一)虚表和虚基表指针

虚函数表(Virtual Function Table)
  • 在C++中,每个类(包括基类和派生类)包含一个虚函数表,也称为虚表(vtable)。虚表是一个包含虚函数指针的数组,每个虚函数指针指向相应虚函数的地址虚表是在编译时创建的,并且对于每个类只有一个
  • 虚表是类的元数据,它记录了该类的虚函数及其位置。当类的对象被创建时,一个指向虚表的指针会添加到对象的内存布局中。
虚表指针
  • 在含有虚函数的类实例化对象时,对象地址的前四个字节存储的指向虚表的指针,它是在构造函数中被初始化的。

虚函数、纯虚函数、多态,C++,c++,开发语言

(二)纯虚函数

纯虚函数(Pure Virtual Function)是C++中的一个特殊类型的虚拟函数,它在基类中声明但没有定义。纯虚函数的声明使用virtual关键字,并在函数声明的末尾添加= 0来表示它是一个纯虚函数。子类(派生类)必须提供纯虚函数的实际实现,否则子类也会被标记为抽象类,无法创建对象。

class Shape {
public:
    // 声明纯虚函数
    virtual void draw() = 0;

    // 普通成员函数
    void displayInfo() {
        // 这里可以包含一些通用的代码
        std::cout << "This is a shape." << std::endl;
    }
};

class Circle : public Shape {
public:
    // 子类必须提供纯虚函数的实现
    void draw() override {
        std::cout << "Drawing a circle." << std::endl;
    }
};

class Square : public Shape {
public:
    // 子类必须提供纯虚函数的实现
    void draw() override {
        std::cout << "Drawing a square." << std::endl;
    }
};

int main() {
    Circle circle;
    Square square;

    circle.displayInfo(); // 调用基类函数
    circle.draw();        // 调用派生类函数

    square.displayInfo(); // 调用基类函数
    square.draw();        // 调用派生类函数

    return 0;
}

在上述示例中,Shape类包含一个纯虚函数draw(),因此Shape类本身是一个抽象类,不能创建它的对象。然后,CircleSquare类都继承自Shape类,并必须提供对draw()的实际实现。这种机制允许多态性(Polymorphism)的实现,允许不同的派生类以不同的方式实现相同的虚拟函数。

二.多态的实现

根据上图举例分析:

#include<iostream>
#include<vector>
using namespace std;
class A {
public:
	virtual void prints() {
		cout << "A::prints" << endl;
	}
	A() {
		cout << "A:构造函数" << endl;
	}
};
class B:public A {
public:
	virtual void prints() {
		cout << "B::prints" << endl;
	}
	B() {
		cout << "B:构造函数" << endl;
	}
};
class C :public A {
public:

};
int main() {
	A *b = new B();
	b->prints();
	b = new C();
	b->prints();
	return 0;
}

虚函数、纯虚函数、多态,C++,c++,开发语言

多态的原理:

1.虚函数表和虚指针(上面)
2.虚函数声明和覆盖
  • 在基类中声明虚函数时,使用virtual关键字。这告诉编译器将该函数视为虚函数,它可以在派生类中被覆盖(重写)。

  • 派生类中的虚函数覆盖基类中的虚函数时,必须使用override关键字,以确保正确的函数被覆盖。这也使得代码更容易阅读和维护

3.动态绑定的过程
  • 当您使用基类指针或引用调用虚函数时,编译器不会在编译时决定要调用哪个函数版本。相反,它会在运行时根据对象的实际类型来选择正确的函数版本。

  • 这个过程大致如下:

    1. 在基类指针或引用上调用虚函数。
    2. 运行时系统会查找对象的虚表指针。
    3. 使用虚表指针找到虚表。
    4. 从虚表中获取正确的函数指针。
    5. 调用相应的函数。
4.多态性的优势
  • 多态性无需关心对象的具体类型,从而提高了代码的可复用性和可维护性。
  • 它允许轻松扩展代码,通过添加新的派生类来增加功能,而不必修改现有的代码。
  • 多态性还支持抽象编程,允许定义基于接口的类,然后通过派生类来实现具体的功能。

总结一下,多态的原理基于虚函数和虚表,它允许在运行时根据对象的实际类型来选择要调用的函数版本,从而实现了面向对象编程中的灵活性和可扩展性。多态性是C++和其他面向对象编程语言的核心概念之一,有助于构建可维护和可扩展的软件系统。

三.为什么析构函数一般写成虚函数?

        由于类的多态性,通常通过父类指针或引用来操作子类对象。因为多态允许我们以统一的方式处理不同的派生类对象,并且在运行时确定要调用的方法。

        如果析构函数不被声明为虚函数,则编译器实施静态绑定,在删除基类指针时,只会调用基类的析构函数而不调用派生类析构函数,这样会造成派生类析构不完全,造成内存泄漏。

        这种行为是为了确保资源的正确释放。由于我们只知道父类的类型,编译器无法确定指针指向的是哪个子类对象,因此只能调用父类的析构函数来释放资源。

没有虚析构:

#include<iostream>
#include<vector>
using namespace std;
class A {
public:
	virtual void prints() {
		cout << "A::prints" << endl;
	}
	A() {
		cout << "A:构造函数" << endl;
	}
	virtual ~A() {
		cout << "A:析构函数 " << endl;
	}
};
class B:public A {
public:
	virtual void prints() {
		cout << "B::prints" << endl;
	}
	B() {
		cout << "B:构造函数" << endl;
	}
	~B() {
		cout << "B:析构函数 " << endl;
	}
};
int main() {
	A *b = new B();
	b->prints();
	delete b;
	b = NULL;
	return 0;
}

虚函数、纯虚函数、多态,C++,c++,开发语言

虚析构:

#include<iostream>
#include<vector>
using namespace std;
class A {
public:
	virtual void prints() {
		cout << "A::prints" << endl;
	}
	A() {
		cout << "A:构造函数" << endl;
	}
	virtual ~A() {
		cout << "A:析构函数 " << endl;
	}
};
class B:public A {
public:
	virtual void prints() {
		cout << "B::prints" << endl;
	}
	B() {
		cout << "B:构造函数" << endl;
	}
	~B() {
		cout << "B:析构函数 " << endl;
	}
};
int main() {
	A *b = new B();
	b->prints();
	delete b;
	b = NULL;
	return 0;
}

 虚函数、纯虚函数、多态,C++,c++,开发语言

分析:可以看到析构函数是,先从子类析构,再到父类析构 文章来源地址https://www.toymoban.com/news/detail-701577.html

到了这里,关于虚函数、纯虚函数、多态的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 从C语言到C++_23(多态)抽象类+虚函数表VTBL+多态的面试题

    目录 1. 多态(polymorphism) 1.1 构成多态的两个条件 1.2 虚函数重写(覆盖) 1.3 协变构成多态 1.4 父虚子非虚构成多态 1.5 析构函数的重写 1.6 final 和 override (C++11) 1.7 重载、覆盖、隐藏的对比 2. 抽象类(Abstract Class) 2.1 纯虚函数和抽象类 2.2 抽象类指针 2.3 接口

    2024年02月13日
    浏览(42)
  • C++|29.纯虚函数/接口(待完成)

    纯虚函数是一种特殊的虚函数。 普通的虚函数允许子类的同名函数对其进行重写,同时普通的虚函数本身是可以单独进行使用的。 而纯虚函数是一个空壳,强制要求所派生的类在继承的过程中必要将该虚函数进行实现。 如上图,纯虚函数只需要在virtual后面添加上=0即可。

    2024年01月16日
    浏览(37)
  • Visual C++中的虚函数和纯虚函数(以外观设计模式为例)

    我是荔园微风,作为一名在IT界整整25年的老兵,今天来说说Visual C++中的虚函数和纯虚函数。该系列帖子全部使用我本人自创的对比学习法。也就是当C++学不下去的时候,就用JAVA实现同样的代码,然后再用对比的方法把C++学会。 直接说虚函数和纯虚函数有很多人会直接晕,但

    2024年02月15日
    浏览(35)
  • Visual C++中的虚函数和纯虚函数(以策略设计模式为例)

    我是荔园微风,作为一名在IT界整整25年的老兵,今天来说说Visual C++中的虚函数和纯虚函数。该系列帖子全部使用我本人自创的对比学习法。也就是当C++学不下去的时候,就用JAVA实现同样的代码,然后再用对比的方法把C++学会。 直接说虚函数和纯虚函数有很多人会直接晕,但

    2024年02月12日
    浏览(47)
  • C++修炼之路之多态---多态的原理(虚函数表)

    目录 一:多态的原理  1.虚函数表  2.原理分析 3.对于虚表存在哪里的探讨 4.对于是不是所有的虚函数都要存进虚函数表的探讨 二:多继承中的虚函数表 三:常见的问答题  接下来的日子会顺顺利利,万事胜意,生活明朗-----------林辞忧  接上篇的多态的介绍后,接下来介绍

    2024年04月26日
    浏览(44)
  • 【C++】多态的概念和简单介绍、虚函数、虚函数重写、多态构成的条件、重载、重写、重定义

        C++中的多态是一种面向对象编程的特性, 它允许不同的对象对同一个消息做出不同的响应。 多态性能够提高代码的可复用性和灵活性,使得代码更加模块化和可扩展。    多态性是通过使用继承和虚函数实现的。 当一个类被声明为虚函数时,它可以被子类重写,并

    2024年02月13日
    浏览(46)
  • 【C++】虚函数与多态

    多态性是面向对象程序设计的重要特征之一,是指发出同样的消息被不同类型的对象接受时有可能导致完全不同的行为。多态的实现:函数重载、运算符重载、模板、虚函数。 静态绑定:绑定过程出现在编译阶段,在编译期就已经确定要调用的函数。 动态绑定:绑定过程工

    2024年02月10日
    浏览(48)
  • 多态与虚函数(补)

    我们首先看下面一段代码 大家可以试着画一下上面三个类的虚表,此处我就不画了 我们试着想一下在上面这三个类型的基础上运行一下代码是否可以运行通过 有的同学可能会说这是可以运行通过的,因为我们的op指向了test对象,这就是错误的理解,该程序在编译时期就会出

    2024年02月05日
    浏览(34)
  • [C++] 多态(上) -- 抽象类、虚函数、虚函数表

    通俗来说,多态就是多种形态, 具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。 举个栗子:比如 买票这个行为: 当 普通人 买票时,是全价买票; 学生 买票时,是半价买票; 军人 买票时是优先买票。 这个例子就是多态,不同身份对应不同的票

    2024年02月04日
    浏览(38)
  • Python函数的重载、多态和继承

    Python重载函数是指函数可以接受不同数量或类型的参数,这样可以使得函数可以处理多种情况。函数重载是指有多个参数签名(即函数在定义时参数个数跟类型)并且有多个舍入函数体实现。也就是, 具有相同名称但实现多个不同的功能 。调用重载函数时,运行时首先评估

    2024年02月05日
    浏览(87)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包