【带头学C++】----- 二、函数章---- 2.5 函数知识补充相关

1.拷贝构造函数(Copy Constructor)

是C++中的特殊成员函数,用于创建一个新对象,并将现有对象的值复制到新对象中。它通常用于在以下情况下创建对象:

  1. 通过一个已存在的对象初始化一个新对象。
  2. 将对象作为参数传递给函数。
  3. 从函数返回一个对象。

拷贝构造函数的定义形式如下:

复制代码
class MyClass {
public:
    MyClass();  // 默认构造函数
    MyClass(const MyClass& other);  // 拷贝构造函数
    // ...
};

拷贝构造函数的参数是对同类型的另一个对象的常引用(const MyClass&)。在创建新对象时,拷贝构造函数会将现有对象的属性值复制到新对象中。

当需要使用拷贝构造函数时,C++会自动调用已定义的拷贝构造函数,例如:

复制代码
MyClass obj1;  // 调用默认构造函数创建一个对象
MyClass obj2(obj1);  // 调用拷贝构造函数,将obj1的值复制到obj2中

在上面的示例中,obj2是通过拷贝构造函数将obj1的值复制到新对象中创建的。需要注意的是,拷贝构造函数是以引用方式传递参数的,这样可以避免不必要的对象拷贝,提高性能。

如果在类定义中未显式定义拷贝构造函数,编译器会提供一个默认的拷贝构造函数。默认的拷贝构造函数会按成员变量的顺序逐个进行拷贝。这种默认的拷贝构造函数适用于大多数情况,但如果类包含指针成员或其他需要特殊处理的资源,通常需要显式定义拷贝构造函数,以确保正确地复制对象的值。

需要注意的是,在某些情况下,可以通过显式删除拷贝构造函数来禁止对象的拷贝,或通过自定义实现来实现特定的拷贝行为。

2.析构函数

析构函数(Destructor)是C++中的特殊成员函数,用于在对象销毁时执行清理操作和释放资源。它的主要功能是回收由对象在其生命周期中分配的资源,如堆内存、打开的文件、网络连接等。

析构函数的名称与类名相同,但在前面加上一个波浪线(~),没有参数和返回类型。它的定义形式如下:

复制代码
class MyClass {
public:
    MyClass();  // 构造函数
    ~MyClass(); // 析构函数
    // ...
};

当一个对象的生命周期结束(销毁)时,C++编译器会自动调用对象的析构函数。析构函数的调用时机有几种情况:

  1. 对象的作用域结束(退出其定义所在的区域);
  2. 动态分配的对象通过delete操作符显式地释放;
  3. 局部对象在函数返回后自动销毁;
  4. 对象是全局变量,程序终止时销毁。

析构函数的主要功能可以有多种应用场景,如关闭文件、释放内存、断开连接等。以下是一个简单的示例,演示了析构函数的基本用法:

复制代码
#include <iostream>

class Resource {
public:
    Resource() {
        std::cout << "Resource acquired." << std::endl;
    }

    ~Resource() {
        std::cout << "Resource released." << std::endl;
    }
};

int main() {
    {
        Resource obj;  // 创建 Resource 对象
    }  // 对象在作用域结束时销毁

    Resource* ptr = new Resource();  // 动态分配的对象
    delete ptr;  // 释放对象

    return 0;
}

在上述示例中,对象obj在其作用域结束时,会自动调用析构函数进行资源的释放。而动态分配的对象ptr需要显式调用delete释放,这样析构函数才会被调用。

需要注意的是,析构函数的定义应该与构造函数的实现一致,以确保资源的正确释放。此外,当一个类需要显式地管理资源的时候,应该实现自定义的析构函数,进行资源回收。

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

由于类的多态性,基类指针可以指向派生类的对象,如果删除该基类的指针,就会调用该指针指向的派生类析构函数,而派生类的析构函数又自动调用基类的析构函数,这样整个派生类的对象完全被释放.

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

所以将析构函数声明为虚函数是十分必要的。在实现多态时,当用基类操作派生类,在析构时防止只析构基类而不析构派生类的状况发生,要将基类的析构函数声明为虚函数。

析构函数一般写成虚函数的原因是为了实现多态性(Polymorphism)和安全的基类指针删除。

  1. 多态性:在面向对象编程中,多态性是指通过基类指针或引用调用派生类对象的成员函数。当基类指针指向派生类对象时,如果基类的析构函数不是虚函数,那么当通过基类指针删除对象时,只会调用基类的析构函数,而不会调用派生类的析构函数。这样就无法正确释放派生类对象中分配的资源,可能导致资源泄漏和未定义行为。通过将析构函数声明为虚函数,可以实现正确的多态性析构,即在删除对象时,会先调用派生类的析构函数,然后再调用基类的析构函数。

  2. 安全的基类指针删除:当使用基类指针指向派生类对象时,如果基类的析构函数不是虚函数,那么当通过基类指针删除对象时,只会调用基类的析构函数,而不会调用派生类的析构函数。这样会导致派生类对象无法正确地释放资源,可能会造成内存泄漏或资源泄漏。通过将析构函数声明为虚函数,可以确保在通过基类指针删除对象时,会依次调用基类和派生类的析构函数,从而正确释放对象及其资源。

因此,将析构函数声明为虚函数是一种良好的编程实践,尤其是当使用多态性和基类指针删除对象时,可以确保正确的对象析构和资源释放。

相关推荐
Wzx1980123 分钟前
go基础语法练习
开发语言·后端·golang
songyuc15 分钟前
《A Bilateral CFAR Algorithm for Ship Detection in SAR Images》译读笔记
人工智能·笔记·计算机视觉
忧郁的蛋~24 分钟前
.NET异步编程中内存泄漏的终极解决方案
开发语言·前端·javascript·.net
2301_7951672029 分钟前
玩转Rust高级应用. ToOwned trait 提供的是一种更“泛化”的Clone 的功能,Clone一般是从&T类型变量创造一个新的T类型变量
开发语言·后端·rust
01100001乄夵32 分钟前
第二课:时序逻辑入门-零基础FPGA闯关教程
经验分享·笔记·学习方法
水月wwww33 分钟前
vue学习之组件与标签
前端·javascript·vue.js·学习·vue
你才是向阳花41 分钟前
如何用Python实现飞机大战小游戏
开发语言·python·pygame
9523642 分钟前
数据结构-链表
java·数据结构·学习
合作小小程序员小小店1 小时前
web网页开发,在线%商城,电商,商品购买%系统demo,基于vscode,apache,html,css,jquery,php,mysql数据库
开发语言·前端·数据库·mysql·html·php·电商
草莓熊Lotso1 小时前
C++ 方向 Web 自动化测试实战:以博客系统为例,从用例到报告全流程解析
前端·网络·c++·人工智能·后端·python·功能测试