零碎的c++二

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

虚函数

虚函数是C++中实现多态的一种机制,它允许通过基类指针或引用来调用派生类的成员函数。虚函数的作用是实现动态绑定,即在运行时根据对象的实际类型来确定调用哪个函数。虚函数的声明方式是在函数前加上关键字virtual,如:

class Base {
public:
    virtual void func(); // 声明一个虚函数
};

虚函数可以有以下几种场景用到:

  • 当我们需要定义一个通用的基类,为不同的派生类提供一个统一的接口时,可以使用虚函数。例如,我们可以定义一个Animal类,为所有动物提供一个虚函数makeSound(),然后让不同的派生类如Dog、Cat等重写这个虚函数,实现各自的叫声。这样,我们就可以通过一个Animal指针或引用来调用任何动物的makeSound()函数,而不需要知道它们的具体类型。
  • 当我们需要利用多态特性来实现一些设计模式时,可以使用虚函数。例如,我们可以使用虚函数来实现模板方法模式,这是一种行为型设计模式,它定义了一个算法的骨架,并将一些步骤延迟到子类中实现。这样,我们可以通过改变子类来改变算法的某些部分,而不影响算法的结构。例如,我们可以定义一个Sorter类,为所有排序算法提供一个虚函数sort(),然后让不同的派生类如BubbleSorter、QuickSorter等重写这个虚函数,实现各自的排序方法。这样,我们就可以通过一个Sorter指针或引用来调用任何排序算法的sort()函数,而不需要知道它们的具体类型。
  • 当我们需要在析构函数中释放一些资源时,可以使用虚函数。如果我们有一个基类指针或引用指向一个派生类对象,并且想要通过它来删除这个对象时,如果基类的析构函数不是虚函数,那么只会调用基类的析构函数,而不会调用派生类的析构函数,这可能导致资源泄漏或内存错误。为了避免这种情况,我们应该将基类的析构函数声明为虚函数,这样就会先调用派生类的析构函数,然后再调用基类的析构函数,从而正确地释放资源。

虚函数和纯虚函数的区别

  • 虚函数是在基类中声明并定义的函数,它在函数前加上关键字virtual,如:
class Base {
public:
    virtual void func(); // 声明一个虚函数
};

虚函数可以在派生类中被override,也就是用不同的实现来替换基类的实现。如果派生类没有override虚函数,那么就会继承基类的实现。虚函数的作用是实现动态绑定,即在运行时根据对象的实际类型来确定调用哪个函数。例如,我们可以定义一个Shape类,为所有图形提供一个虚函数area(),然后让不同的派生类如Circle、Rectangle等override这个虚函数,实现各自的面积计算方法。这样,我们就可以通过一个Shape指针或引用来调用任何图形的area()函数,而不需要知道它们的具体类型。

  • 纯虚函数是在基类中声明但不定义的函数,它在函数后加上=0,如:
class Base {
public:
    virtual void func() = 0; // 声明一个纯虚函数
};

纯虚函数没有默认的实现,它要求任何派生类都必须提供自己的实现方法。如果派生类没有提供纯虚函数的实现,那么这个派生类也不能被实例化。纯虚函数的作用是定义一个接口,规范派生类的行为。例如,我们可以定义一个Animal类,为所有动物提供一个纯虚函数makeSound(),然后要求所有派生类如Dog、Cat等必须实现这个纯虚函数,提供各自的叫声方法。这样,我们就可以通过一个Animal指针或引用来调用任何动物的makeSound()函数,而不需要知道它们的具体类型。

  • 虚函数和纯虚函数的区别主要有以下几点:

    • 虚函数可以有默认的实现,纯虚函数没有默认的实现。
    • 虚函数可以被派生类继承或override,纯虚函数必须被派生类override。
    • 虚函数可以通过基类指针或引用调用基类或派生类的实现,纯虚函数只能通过基类指针或引用调用派生类的实现。
    • 包含虚函数的类可以被实例化,包含纯虚函数的类不能被实例化,称为抽象类。
  • 虚函数和纯虚函数的使用场景主要有以下几种:

    • 当我们需要定义一个通用的基类,为不同的派生类提供一个统一的接口时,可以使用虚函数。例如,我们可以定义一个Shape类,为所有图形提供一个虚函数area()。
    • 当我们需要利用多态特性来实现一些设计模式时,可以使用虚函数。例如,我们可以使用虚函数来实现模板方法模式,这是一种行为型设计模式,它定义了一个算法的骨架,并将一些步骤延迟到子类中实现。
    • 当我们需要在析构函数中释放一些资源时,应该使用虚析构函数。如果我们有一个基类指针或引用指向一个派生类对象,并且想要通过它来删除这个对象时,如果基类的析构函数不是虚析构函数,那么只会调用基类的析构函数,而不会调用派生类的析构函数,这可能导致资源泄漏或内存错误。为了避免这种情况,我们应该将基类的析构函数声明为虚析构函数,这样就会先调用派生类的析构函数,然后再调用基类的析构函数,从而正确地释放资源。
    • 当我们需要定义一个抽象的基类,规范派生类的行为,但不提供默认的实现时,可以使用纯虚函数。例如,我们可以定义一个Animal类,为所有动物提供一个纯虚函数makeSound()。

深拷贝和浅拷贝

C++中的深拷贝和浅拷贝是指在对象复制时,对于类中的资源(如动态内存、文件句柄等)的处理方式。具体来说:

  • 浅拷贝是指只复制对象的基本类型成员变量和指针类型成员变量的值,而不复制指针所指向的资源。这样,原对象和新对象会共享同一块资源,如果其中一个对象修改或释放了资源,会影响另一个对象的状态。浅拷贝是编译器默认提供的拷贝行为,一般适用于类中没有资源或不需要管理资源的情况。
  • 深拷贝是指除了复制对象的基本类型成员变量和指针类型成员变量的值外,还会为指针所指向的资源重新分配内存,并复制资源内容。这样,原对象和新对象会拥有各自独立的资源,互不影响。深拷贝需要程序员显式地定义拷贝构造函数和赋值运算符重载函数,以实现自定义的拷贝行为。深拷贝一般适用于类中有资源并需要管理资源的情况。

下面是一个简单的例子来说明深拷贝和浅拷贝的区别:

#include <iostream>
using namespace std;

class Person {
public:
    // 有参构造函数
    Person(int age, int height) {
        m_age = age;
        m_height = new int(height); // 动态分配内存
    }
    // 拷贝构造函数
    Person(const Person& p) {
        m_age = p.m_age;
        // m_height = p.m_height; // 浅拷贝
        m_height = new int(*p.m_height); // 深拷贝
    }
    // 析构函数
    ~Person() {
        if (m_height != NULL) {
            delete m_height; // 释放内存
            m_height = NULL;
        }
    }
    // 打印信息
    void show() {
        cout << "age: " << m_age << ", height: " << *m_height << endl;
    }
private:
    int m_age; // 年龄
    int* m_height; // 身高
};

int main() {
    Person p1(18, 180); // 创建一个Person对象
    p1.show(); // 打印信息
    Person p2(p1); // 用p1初始化p2,调用拷贝构造函数
    p2.show(); // 打印信息
    *p2.m_height = 190; // 修改p2的身高
    p2.show(); // 打印信息
    p1.show(); // 打印信息
    return 0;
}

如果使用浅拷贝,那么输出结果为:

age: 18, height: 180
age: 18, height: 180
age: 18, height: 190
age: 18, height: 190

可以看到,修改p2的身高也影响了p1的身高,这是因为p1和p2共享了同一块内存。另外,在析构函数中释放内存时,也会出现重复释放或野指针的问题。

如果使用深拷贝,那么输出结果为:

age: 18, height: 180
age: 18, height: 180
age: 18, height: 190
age: 18, height: 180

可以看到,修改p2的身高不影响p1的身高,这是因为p1和p2各自拥有了独立的内存。另外,在析构函数中释放内存时,也不会出现问题。文章来源地址https://www.toymoban.com/news/detail-707383.html

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

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

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

相关文章

  • openpnp - 设备矫正的零碎记录

    设备矫正终于正常通过了… 从头进行多次设备校验, 都能一次性校验通过, 重复性很好. 补充一些矫正过程中的细节. 同学说我是过度矫正, 太不负责任了, 听的我浑身难受. 同学做的任何事情, 都是抱着凑合的态度来做事, 这对自己和别人都不好啊. 这样做事, 口碑都没了. 这次定

    2024年02月15日
    浏览(56)
  • .NET Core基础到实战案例零碎学习笔记

    前言:前段时间根据 [老张的哲学] 大佬讲解的视频做的笔记,讲的很不错。此文主要记录JWT/DI依赖注入/AOP面向切面编程/DTO/解决跨域等相关知识,还包含一些.NET Core项目实战的一些案例。我是西瓜程序猿,感谢大家的支持! 1.1.1-.NET Croe简介 (1)为什么要学习.NET Core? .NET

    2024年02月12日
    浏览(39)
  • C语言零碎知识点之字符串数组

    在C语言中字符串数组有两种表示方法: 第一种, 二维字符数组 可以利用二维字符数组来表示字符串,格式是: char strs[row][col]; 。例如: 其中的 row 表示二维数组中的行,表示有几个字符串;而 col 表示二维数组中的列,表示能存放字符串的最大长度。 第二种, 字符指针数

    2024年01月18日
    浏览(50)
  • 【零碎知识】pip install 与 conda install 的区别

    先说结论:推荐优先使用 conda 管理环境和包 pip 和 conda 是两个常用的包管理工具,它们在多个方面存在差异: 管理系统: pip 是Python包的管理工具,通常用于安装来自Python包索引(PyPI)的软件包。 conda 是一个跨平台的包管理和环境管理系统,可以用于安装Python软件包以及其

    2024年01月25日
    浏览(47)
  • 传输层中一些零碎且易忘的知识点

    端口号:共两个字节 不同类型的端口号: 服务端端口号 熟知端口号:0~1023 登记端口号:1024~49151 客户端使用端口号(短暂/临时端口号):49152~65535 要记得常见应用程序的熟知端口号 FTP:21 TELNET:23 SMTP:25 DNS:53 TFTP:69 HTTP:80 SNMP:161 首部与伪首部: 伪首部中协议字

    2024年02月15日
    浏览(39)
  • 网络层中一些零碎且易忘的知识点

    异构网络:指传输介质、数据编码方式、链路控制协议以及数据单元格式和转发机制不同,异构即物理层和数据链路层均不同 虚电路:网络层可以向传输层提供两种类型的服务,面向连接的服务称为虚电路服务,而无连接的服务称为数据报服务。虚电路的想法是避免为发送的

    2024年02月15日
    浏览(42)
  • 数据结构中一些零碎且易忘的知识点

    第一章 绪论 数据结构包含三个方面的内容: 数据的逻辑结构:描述数据之间逻辑关系的、与数据的存储无关的数学模型。相同的逻辑结构可使用不同的存储结构存储,如线性表既可顺序存储,也可链式存储 线性结构:一个线性表是n个具有相同特性的数据元素的有限序列 一

    2024年02月14日
    浏览(41)
  • 数据链路层中一些零碎且易忘的知识点

    差错控制 差错的种类: 位错(比特错):0变1、1变0(这类差错是本节所探讨的差错) 帧错:帧丢失、帧重复、帧失序(这类差错只在提供可靠传输的数据链路层中才进行修复) 要记的编码(数据链路层可使用只检测差错的编码,也可使用纠错编码) 检错编码: 奇偶校验码

    2024年02月15日
    浏览(40)
  • 【零碎小知识】【python】selenium.common.exceptions.InvalidArgumentException: Message: invalid argument: inval

    就在之前还可以运行的爬虫代码,电脑重启之后就不能运行了。。。,显示错误原因如下: selenium.common.exceptions.InvalidArgumentException: Message: invalid argument: invalid locator (Session info: chrome=98.0.4758.82) 意思是: 消息:无效的参数:无效的定位器 (会话信息:chrome = 98.0.4758.82) 这是我的代码

    2024年02月11日
    浏览(40)
  • 【webpack】一些零碎的知识点记录:eslint配置、source-map配置、devServer配置

    有些知识点不知道咋归类,就先暂时放在同一个文章里了。这里只记录配置方式,配置的东西是什么就不过多解释了,因为一般需要配置这些东西的也都了解是什么了。 一般在用cli创建vue工程或者cra创建react工程的时候,会默认帮你安装,webpack会自动帮你配置好,我也比较推

    2024年02月13日
    浏览(45)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包