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

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

相关推荐
懒惰的bit2 小时前
基础网络安全知识
学习·web安全·1024程序员节
SRY122404192 小时前
javaSE面试题
java·开发语言·面试
lb36363636363 小时前
介绍一下数组(c基础)(详细版)
c语言
李元豪3 小时前
【智鹿空间】c++实现了一个简单的链表数据结构 MyList,其中包含基本的 Get 和 Modify 操作,
数据结构·c++·链表
2401_858286113 小时前
L7.【LeetCode笔记】相交链表
笔记·leetcode·链表
无尽的大道3 小时前
Java 泛型详解:参数化类型的强大之处
java·开发语言
ZIM学编程3 小时前
Java基础Day-Sixteen
java·开发语言·windows
放逐者-保持本心,方可放逐3 小时前
react 组件应用
开发语言·前端·javascript·react.js·前端框架
UestcXiye3 小时前
《TCP/IP网络编程》学习笔记 | Chapter 9:套接字的多种可选项
c++·计算机网络·ip·tcp
一丝晨光4 小时前
编译器、IDE对C/C++新标准的支持
c语言·开发语言·c++·ide·msvc·visual studio·gcc