C++面向对象编程<六>:Big Three,三个特殊函数

本文详细介绍了C++类中如何实现深度拷贝和浅度拷贝,包括构造函数、拷贝构造函数、析构函数及拷贝赋值运算符的实现,以及内存管理的重要性。

简介

这里看class的另一个分类:class with pointer members.
先看String的声明

#ifndef _MYSTRING_
#define _MYSTRING_

class String
{
    public:
        String(const char* cstr = 0);
        String(const String& str);                //拷贝构造 
        String& operator = (const String& str);  //拷贝赋值 
        ~String();
        char* get_c_str const () {return m_data};
    private:
        char* m_data;   
};

#endif

如上所示:Big Three,三个特殊的函数:拷贝构造函数、拷贝赋值函数、析构函数。其实不写,编译器也会有默认的这些函数,那么什么时候需要写呢?就得看看编译器默认的这些函数够不够用。(默认的就是一个个位进行复制)
class with pointer members一般这样设计:指针作为成员变量,在需要内存的时候动态申请,而不是直接在class里放数组,因为不知道数组需要多大。显然得自己写Big three函数
class with pointer members 就一定要写构造函数、拷贝构造函数、析构函数

构造函数和析构函数

先看构造函数的实现

inline String::String(const char* cstr = 0)
{
    if (cstr)
    {
        m_data = new char[strlen(cstr) + 1];
        strcpy(m_data,cstr);
    }
    else //未指定值,形成空字符串 
    {
        m_data = new char[1];
        *m_data = '\0';
    }
}

析构函数需要清理空间,这里的class有动态申请空间,若没有释放掉的话,会有内存泄露

inline String::~String()
{
    delete [] m_data;
}

拷贝构造函数

如上String的设计,使用如下

String a("Hello");
String b("World");
b = a;

String类只包含m_data指针,并不包含其申请的动态空间,
如果使用默认拷贝构造函数,编译器会自己一个字节一个字节的复制,会出现的y严重的后果。如果把a的内容复制到b中去,就会出现a的m_data和b的m_data指向一个地方,那么b指向的内容”World”就没有指针指向他了,会出现内存泄露。而赋值后两个指针指向一块内存也很危险:你更改a,b就会受影响,所以这种叫浅拷贝,只会拷贝指针。会有两个隐患。(见下示意图)
这里写图片描述

改进方法就是使用深拷贝,如下
要去写的就是深拷贝
先看拷贝构造函数,如下

String::String(const String& str)
{
    m_data = new char[ strlen(str.m_data + 1) ];
    strcpy(m_data,str.m_data);
}

使用如下

String s1("Hello");
String s2(s1);     //以s1为蓝本、初值创建s2
String s3 = s1;    //调用拷贝构造函数 //把s1赋值到s3上,但s3也是新创建的对象(既然新创建的就要调用构造函数)。

拷贝赋值

使用如下

b = a;

首先明白:b和a对象都有内容,那么把b赋值给a,需要以下三个步骤
三步骤:先清空b的内容,再为b分配一个空间,然后再将a的内容拷贝过来给b。
下面看函数

inline String& String::operator = (const String& str)
{
    if (this == &str)  //检测自我赋值 
        return *this;

    delete[] m_data;
    m_data = new char[ strlen(str.m_data + 1)];
    strcpy(m_data,str.m_data);
    return *this;
}

注意:自我赋值检测的必要性,谁会做自我赋值的动作呢?所以说这样效率高,
如果没有写这两行,不仅仅是效率问题。如果没有这两行,可以试试赋值自己会出现什么bug。所以我自我赋值的检测是必要的

再看一个程序,看下什么时候调用 big three 函数

String str1("hello");  //调用构造函数
String str2(str1);    //调用拷贝构造函数
String str3 = str1;   //调用拷贝构造函数
str3 = str2;          //调用拷贝赋值函数

先给出String的完整程序

#ifndef __MYSTRING__
#define __MYSTRING__

class String
{
public:                                 
   String(const char* cstr=0);                     
   String(const String& str);                    
   String& operator=(const String& str);         
   ~String();                                    
   char* get_c_str() const { return m_data; }
private:
   char* m_data;
};

#include <cstring>

inline
String::String(const char* cstr)
{
   if (cstr) {
      m_data = new char[strlen(cstr)+1];
      strcpy(m_data, cstr);
   }
   else {   
      m_data = new char[1];
      *m_data = '\0';
   }
}

inline
String::~String()
{
   delete[] m_data;
}

inline
String& String::operator=(const String& str)
{
   if (this == &str)
      return *this;

   delete[] m_data;
   m_data = new char[ strlen(str.m_data) + 1 ];
   strcpy(m_data, str.m_data);
   return *this;
}

inline
String::String(const String& str)
{
   m_data = new char[ strlen(str.m_data) + 1 ];
   strcpy(m_data, str.m_data);
}

#include <iostream>
using namespace std;

ostream& operator<<(ostream& os, const String& str)
{
   os << str.get_c_str();
   return os;
}

#endif
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值