首页 > 其他分享 ><三>对象的浅拷贝和深拷贝问题

<三>对象的浅拷贝和深拷贝问题

时间:2022-11-13 11:24:29浏览次数:39  
标签:char pchar 对象 age len 问题 int pName 拷贝

先看示例代码

点击查看代码
#include <iostream>
 #include<cstring>
using namespace std;

class Student{

public:

    Student(int _age , const char * _name)
    {
         
         this->age=_age;

         int len=strlen(_name)+1;

         char *tep=new char[len];

         this->pName=tep;

         strcpy(this->pName,_name);

    }

    ~Student(){
        
        delete[]this->pName;
        this->pName=nullptr;
       
    }

    void showStudent(){
        cout<<this->pName<<" "<<this->age<<endl;
    }

 private:
    int  age;
    char *pName;  
};


int main(){

   Student s1(20,"zhangsan");
   s1.showStudent();

   Student s2=s1;
  
   s2.showStudent();

   return 1;
}

上面示例代码中,对象的默认拷贝方式是内存数据拷贝,如果对象占用了外部资源,那么就会出现问题了,这里的外部资源
就是在堆上申请的空间存放名字用,
s1,s2两个对象中的名字指针都是指向了同一块堆内存区域,在结束main函数的是,s2先析构,s2会析构调堆上的内存空间,
s1再析构,由于s1对象的pName 指针和s2对象的pName指针指向的是同一块堆内存区域,但是该区域内存已经被释放了,所以遇到了问题

鉴于上面的问题,我们引出了 浅拷贝,深拷贝的问题和解决方法.

Student s2=s1; 会调用拷贝构造函数(该拷贝构造函数可以是系统自动生成的,或者你自己定义一个拷贝构造函数)
系统自动生成的拷贝构造函数做的是内存数据拷贝,所以就出现了上面的问题.因此我们需要定义属于自己的拷贝构造函数

改造代码如下

点击查看代码
class Student2{

public:

    Student2(int _age , const char * _name)
    {        
         this->age=_age;
         int len=strlen(_name)+1;
         char *tep=new char[len];   
         this->pName=tep;
         strcpy(this->pName,_name);
         cout<<"执行构造函数"<<endl;
    }

    //自定义拷贝构造函数
    Student2(const Student2 &_stu2){

        this->age=_stu2.age;    
        int len =strlen(_stu2.getPName())+1;
        char *newPName =new char[len];
        this->pName=newPName;
        strcpy(this->pName,_stu2.getPName());
        cout<<"执行拷贝构造函数"<<endl;

    }

    ~Student2(){
        if(this->pName!=nullptr){
            delete[]this->pName;
            this->pName=nullptr;
        }
    }

    void showStudent(){

        int *p=(int *)this->pName;
        cout<<this->pName<<" "<<this->age<<" pName Heap Address ="<<p<<endl;

    }

    const char * getPName() const{
         return this->pName;
    }

 private:
    int  age;
    char *pName;  

};




int main(){

   Student2 s1(20,"zhangsan");
   
   s1.showStudent();

   Student2 s2=s1;

   s2.showStudent(); 


   return 1;
}

上面的代码还存在一个问题如下,如果在main函数中是下面的代码

Student2 s1(20,"zhangsan");

Student2 s2(30,"lisi");

s2=s1;

在main函数结束的是同样会遇到问题,这个时候就引出 赋值函数,我们需要定义自己的赋值函数

在 s2=s1这一段代码其实是这样调用的
s2.operator=(s1)

在你不定义自己的赋值函数的时候,系统会帮我们生成一个赋值函数,该赋值函数的赋值方式就是内存的数值拷贝,这种方式
在Student对象,会有问题,所以我们需要向自定义拷贝构造一样,定义一个属于自己的赋值函数

代码如下

点击查看代码
class Student3{

public:

    Student3(int _age , const char * _name)
    {        
         this->age=_age;
         int len=strlen(_name)+1;
         char *tep=new char[len];   
         this->pName=tep;
         strcpy(this->pName,_name);
         cout<<"执行构造函数"<<endl;
    }

    //自定义拷贝构造函数
    Student3(const Student3 & _stu){

        this->age=_stu.age;    
        int len =strlen(_stu.getPName())+1;
        char *newPName =new char[len];
        this->pName=newPName;
        strcpy(this->pName,_stu.getPName());
        cout<<"执行拷贝构造函数"<<endl;

    }

    //自定义赋值函数
    Student3 & operator= (const Student3 & _stu){

        //防止自赋值
        if(this==&_stu){return *this;}

        //注意: 需要先释放当前的堆内存空间!!
        delete []this->pName;

        this->age=_stu.age;    
        int len =strlen(_stu.getPName())+1;
        char *newPName =new char[len];
        this->pName=newPName;
        strcpy(this->pName,_stu.getPName());
        cout<<"执行赋值函数"<<endl;
        return *this;
    }

    ~Student3(){
        if(this->pName!=nullptr){
            delete[]this->pName;
            this->pName=nullptr;
        }
    }

    void showStudent(){

        int *p=(int *)this->pName;
        cout<<this->pName<<" "<<this->age<<" pName Heap Address ="<<p<<endl;

    }

    const char * getPName() const{
         return this->pName;
    }

 private:
    int  age;
    char *pName;  

};

int main(){

   Student3 s3(20,"zhangsan");
   
   s3.showStudent();

   Student3 s4(30,"lisi");

   s4=s3;
   
   s4.showStudent();

   return 1;
}

运用深拷贝浅拷贝实现String 代码如下

点击查看代码
#include <iostream>
#include <cstring>
using namespace std;

class MyString{

public:

     //构造函数
     MyString(const char * src){

        //创建空串
        if(src==nullptr){
            this->pchar=new char[1];
            this->pchar[0]='\0';
        }
        else{
            int len =strlen(src)+1;
            this->pchar=new char[len];
            strcpy(this->pchar,src);
        }
        cout<<"执行构造函数, 堆内存空间地址"<<(int *)this->pchar <<endl;

     }

     //拷贝构造
     MyString(const MyString & myString){
      
        //重新分配内存空间 
        int len =myString.stringLen()+1;
        this->pchar=new char[len];
        strcpy(this->pchar,myString.pchar);  
        cout<<"执行拷贝构造函数, 新创建堆内存空间地址"<<(int *)this->pchar <<endl;
 
     }

     //赋值函数
     MyString & operator=(const MyString & myString){

         //防止自赋值
         if(this==&myString){return *this;}
         //释放现有的堆内存空间
         delete[]this->pchar;
         this->pchar=nullptr;

        int len =myString.stringLen()+1;

        this->pchar=new char[len];
        strcpy(this->pchar,myString.pchar);
        
        cout<<"执行赋值函数, 新创建堆内存空间地址"<<(int *)this->pchar <<endl;

        return *this;

     }

     int stringLen() const {     
         return strlen(this->pchar);
     }
    
     //析构
     ~MyString(){
         delete [] this->pchar;
         this->pchar=nullptr;
     }

     void printChar() const{      
         cout<<this->pchar<<endl;
     }

private:
    char *pchar;
   

};


int main(){

    MyString s1("abcd");
    s1.printChar();

    MyString s2=s1;//执行拷贝构造
    s2.printChar();

    MyString s3("1234");
    s3=s1;//执行赋值函数
    s3.printChar();

    
    return 1;
}

标签:char,pchar,对象,age,len,问题,int,pName,拷贝
From: https://www.cnblogs.com/erichome/p/16884566.html

相关文章

  • 实验二 电梯问题
    代码地址:Test/电梯问题.cppatmain·AILYNNX/Test(github.com)实验截图:运行截图: ......
  • 显示欧拉法求解 y' = y 问题
    简介最近无聊看了一下数值解法已知\(\frac{dy}{dx}=y\)我们知道其有一个解析解为\(y=e^x\)同时我们知道其初值\(y(0)=1\),x的范围为\(0<=x<=1\)......
  • 两个动态规划的经典问题
    硬币问题问题描述:设有n种不同面值的硬币,各硬币的面值存于数组T[1:n]中。现要用这些面值的硬币来找钱。可以使用的各种面值的硬币个数存于数组Coins[1:n]中。对任意钱数0......
  • 第6章Spring与Web-使用 Spring 的监听器 ContextLoaderListener使得将spring容器对象
    第6章Spring与Web在Web项目中使用Spring框架,首先要解决在web层(这里指Servlet)中获取到Spring容器的问题。只要在web层获取到了Spring容器,便可从容器中获取到......
  • EasyExcel低版本中数据行中包含空数据会跳过导致数据对应不上的问题解析
    文章摘自:https://blog.csdn.net/caijwjava/article/details/100855361实战1、导入一个相关依赖即可<dependency><groupId>com.alibaba</groupId><artifactId>easyexc......
  • 快速排序需要注意的问题
    1  左右哨兵等于pivot的情况要接着走,不然有可能一直不动,无限循环2  需要先走右指针再走左指针,因为pivot在最左侧,最终停留点应该比pivot小,这样交换后小的在前; ......
  • 动态规划经典问题相关博文
    0-1背包:Tyler_Zx双机调度:nudt_oys装载问题:Stars-one......
  • 02类与对象-动手动脑
    代码:classRoot{ static { System.out.println("Root的静态初始化块"); } { System.out.println("Root的普通初始化块"); } publicRoot() { System.out.println("Root......
  • 02-类与对象-一个有趣的问题
    静态方法中只允许访问静态数据,那么,如何在静态方法中访问类的实例成员(即没有附加static关键字的字段或方法)? 代码:package test; publicclassjingtaihanshu{in......
  • 02类与对象--ObjectEquals
    代码:publicclassObjectEquals{ publicstaticvoidmain(String[]args) { MyTestClassobj1=newMyTestClass(100); MyTestClassobj2=newMyTestClass(100);......