实例展示C++复制构造函数和赋值运算符函数的使用

15 篇文章 0 订阅

C++的复制构造函数和赋值运算符函数究竟有什么用呢?下面通过示例来展示其用法,特别注意几处容易忽略的地方。

先定义两个数据结构:

// @type UWORD    | 2 byte unsigned integer.  
typedef unsigned short UWORD;  
  
// @type SDWORD   | 4 byte signed integer.  
typedef signed long SDWORD;

//data definition.
struct Electron
{
    SDWORD ID_len;
    DWORD ID_status;
    int ID;
    
    SDWORD KeyCode_len;
    DWORD KeyCode_status;
    char KeyCode[64];
    
    SDWORD DeviceNumber_len;
    DWORD DeviceNumber_status;
    char DeviceNumber[64];    

    SDWORD DeviceID_len;
    DWORD DeviceID_status;
    int DeviceID;

    SDWORD DeviceType_len;
    DWORD DeviceType_status;
    int DeviceType;

    SDWORD DeviceName_len;
    DWORD DeviceName_status;
    char DeviceName[64];

    SDWORD DataState_len;
    DWORD DataState_status;
    int DataState;

    SDWORD DataValue_len;
    DWORD DataValue_status;
    float DataValue;

    SDWORD StateName_len;
    DWORD StateName_status;
    char StateName[64];

    SDWORD RegionBegin_len;
    DWORD RegionBegin_status;
    float RegionBegin;
    
    SDWORD RegionEnd_len;
    DWORD RegionEnd_status;
    float RegionEnd;
    
    SDWORD UTCTime_len;
    DWORD UTCTime_status;
    char UTCTime[32];
};

class DeviceData
{
public:
    DeviceData();
    ~DeviceData();

    DeviceData(const DeviceData&data);  //定义一个复制构函函数

    void operator=(const DeviceData& data); //定义一个赋值运算符函数

public:

    int ItemCount;

    vector<Electron>* m_pItemList;//这里定义一个指针

};

下面为其实现:

DeviceData::DeviceData()
{
    m_pItemList = new vector<Electron>();
}

DeviceData::DeviceData(const DeviceData& data)
{
    this->m_pItemList = new vector<Electron>();
    this->ItemCount = data.ItemCount;
    if(data.m_pItemList->size()>0)
    {
        this->m_pItemList->assign(data.m_pItemList->begin(),data.m_pItemList->end());
    }
}

DeviceData::~DeviceData()
{
    if(m_pItemList != NULL)
    {
        m_pItemList->clear();
        delete m_pItemList;
        m_pItemList = NULL;
    }
}

void DeviceData::operator=(const DeviceData& data)
{
    //注意,和复制构造函数的区别是,本身对象已经存在,所以this->m_pItemList指针是已经存在的。
    this->m_pItemList->clear();
    this->ItemCount = data.ItemCount;
    if(data.m_pItemList->size()>0)
    {
        this->m_pItemList->assign(data.m_pItemList->begin(),data.m_pItemList->end());
    }
}

//下面是调用代码:

    //1. 创建而没有赋值,调用构造函数。
   DeviceData data;  //这样调用构造函数
   data.ItemCount = 100;

   Electron elem;
   elem.DataValue = 100;
   char* pstr = "1111111111111";
   memcpy(elem.DeviceNumber,pstr,strlen(pstr)+1);
   data.m_pItemList->push_back(elem);

   //2. 创建的同时用另一个已有的对象来赋值,调用复制构造函数。
   DeviceData dest1(data);//这样调用复制构造函数
   DeviceData dest2 = data;//这样调用复制构造函数

  //3. 对象已创建,调用另一个对象来赋值,调用赋值运算符函数。
   DeviceData dest3;  //调用构造函数
   dest3 = data;  //赋值,调用赋值运算符函数。

注意以上代码,构造了4次,那么退出调用的代码块之后,将用调用4次析构函数。因为定义了指针,如果不显示的定义复制构造函数,那么在析构的时候,通过复构构造的多个实例的m_pItemList指针是同一个地址,必定会重复释放从而引起异常而崩溃。而如果m_pItemList不是指针,则不用显示定义自己的复制构造函数。同理,如果包含指针成员,则也必须定义自己的赋值运算符 函数。

下面展示一下函数调用时,传实体的引用与传实体值的区别:

传引用调用函数:

void CallDeviceData(const DeviceData& data)
{
    if(data.ItemCount>0)
    {
        //do something.    
    }
}

调用:

   DeviceData data;  
   data.ItemCount = 100;

   CallDeviceData(data);  //这是传引用,出函数后,不会调用析构函数。

//入函数体调用复制构造函数,出函数体调用析构函数。

void CallDeviceData(const DeviceData data)
{
    if(data.ItemCount>0)
    {
        //do something.    
    }
}

调用:

   DeviceData data;  
   data.ItemCount = 100;

   CallDeviceData(data); // 这是传值调用,实际上,入函数时系统会调用复制构造函数复制一个副本,退出函数后,这个副本会调用析构函数。

注意了,这里退出调用块之后,析构函数会调用两次,一次是data的析构,一次调用函数时产生的副本的析构。

从以上可以看出,对于定义了指针的类,一定要定义自己的复制构造函数和赋值运算符函数。

 

 

 

 

 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值