IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++学习 十五、类继承(6)动态内存 -> 正文阅读

[C++知识库]C++学习 十五、类继承(6)动态内存

前言

本篇继续学习类继承中的动态内存问题。

C++类中如果创建了动态内存,则需要手动提供复制构造函数,析构函数和重载赋值运算符,以防止内存泄漏和double free问题。

基类的动态内存

之前的博客中提到,如果类内分配了动态内存,则必须手动提供复制构造函数,析构函数和重载赋值运算符。

在基类中new一块动态内存的示例如下:

class Base{
    private:
        int* pa_;
    public:
        Base();
        Base(const Base&);
        ~Base();
        Base& operator= (const Base&);
};

Base::Base(){
    std::cout << "base default constructor" << std::endl;
    pa_ = new int [5];
    pa_[0] = 0;
    pa_[1] = 1;
    pa_[2] = 2;
    pa_[3] = 3;
    pa_[4] = 4;
}

Base::Base(const Base& obj){
    std::cout << "base copy constructor" << std::endl;
    int len = 5;
    pa_ = new int [len];
    for(int i=0;i < len; i++)
    {
        pa_[i] = (obj.pa_)[i];
        std::cout << pa_[i] << " ";
    }
    std::cout << std::endl;
}

Base::~Base(){
    std::cout << "base destructor" << std::endl;
    delete [] pa_;
}

Base& Base::operator= (const Base& obj){
    std::cout << "base assign constructor" << std::endl;
    if(this == &obj)
        return *this;
    delete [] pa_;
    int len = 5;
    pa_ = new int [len];
    for(int i=0;i < len; i++)
    {
        pa_[i] = (obj.pa_)[i];
        std::cout << pa_[i] << " ";
    }
    std::cout << std::endl;
    return *this;
}

基类的实现与普通类使用动态内存的实现一致。

派生类的动态内存

如果基类使用了动态内存,那么派生类的实现将有两种情况。

派生类不使用动态内存

如果派生类不使用动态内存,则可以不手动提供派生类的析构函数,复制构造函数和赋值运算符。

派生类默认的析构函数将调用基类的析构函数释放基类分配的动态内存。

派生类默认的复制构造函数将首先调用基类的复制构造函数创建基类对象,然后再创建派生类对象。

派生类默认的赋值运算符将自动使用基类重载的赋值运算符为基类对象赋值,然后再为派生类对象赋值。

派生类对象的部分没有涉及到动态内存,因此默认上述函数的默认形式都没有问题。

派生类使用动态内存

此时,派生类需要手动提供析构函数,复制构造函数和重载赋值运算符。

派生类的析构函数会自动调用基类的析构函数,因此只需要将派生类部分清理即可。

派生类的复制构造函数应当在成员初始化列表中显式调用基类的复制构造函数,然后再初始化派生类成员。

派生类的赋值运算符应当显式调用基类的赋值运算符。

示例如下:

class Derived : public Base{
    private:
        int* pb_;
    public:
        Derived();
        Derived(const Derived&);
        ~Derived();
        Derived& operator= (const Derived&);
};

Derived::Derived(): Base(){
    std::cout << "derived default constructor" << std::endl;
    pb_ = new int [5];
    pb_[0] = 10;
    pb_[1] = 11;
    pb_[2] = 12;
    pb_[3] = 13;
    pb_[4] = 14;
}

Derived::~Derived(){
    std::cout << "derived destructor" << std::endl;
    delete [] pb_;
}

Derived::Derived(const Derived& obj): Base(obj){
    std::cout << "derived copy constructor" << std::endl;
    int len = 5;
    pb_ = new int [len];
    for(int i=0; i < 5; i++)
    {
        pb_[i] = (obj.pb_)[i];
        std::cout << pb_[i] << " ";
    }
    std::cout << std::endl;
}

Derived& Derived::operator= (const Derived& obj){
    std::cout << "derived assign constructor" << std::endl;
    if(this == &obj)
        return *this;
    Base::operator= (obj);
    delete [] pb_;
    int len = 5;
    pb_ = new int [len];
    for(int i=0; i < len; i++)
    {
        pb_[i] = (obj.pb_)[i];
        std::cout << pb_[i] << " ";
    }
    std::cout << std::endl;
    return *this;
}

~Derived()派生类析构函数隐含调用了的基类析构函数。

Derived::Derived(const Derived& obj)派生类复制构造函数在成员初始化列表中首先创建了基类对象。

Derived& Derived::operator= (const Derived& obj)派生类赋值运算符中,通过Base::operator=(obj);显式调用了基类的赋值运算符。

最终结果:

base default constructor
derived default constructor
base copy constructor
0 1 2 3 4 
derived copy constructor
10 11 12 13 14 
derived assign constructor
base assign constructor
0 1 2 3 4 
10 11 12 13 14 
derived destructor
base destructor
derived destructor
base destructor
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-03 15:50:34  更:2022-03-03 15:55:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 4:26:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码