文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

C++实现拷贝构造函数的方法详解

2024-04-02 19:55

关注

引入

对于普通类型的对象来说,他们之间的复制很简单:

int a = 10;
int b = a;

但是对于类对象来说,其中会存在许多的成员变量。

#include <iostream>
using namespace std;

class CExample {
private:
     int a;
public:
      //构造函数
     CExample(int b)
     { a = b;}

      //一般函数
     void Show ()
     {
        cout<<a<<endl;
      }
};

int main()
{
     CExample A(100);
     CExample B = A; //注意这里的对象初始化要调用拷贝构造函数,而非赋值
      B.Show ();
     return 0;
}

从以上代码可以看出系统为对象 B 分配了内存并完成了与对象 A 的复制过程。就类对象而言,相同类型的类对象是通过拷贝构造函数来完成整个复制过程的。

下面这个则是拷贝构造函数的工作过程

#include <iostream>
using namespace std;

class CExample {
private:
    int a;
public:
    //构造函数
    CExample(int b)
    { a = b;}
    
    //拷贝构造函数
    CExample(const CExample& C)
    {
        a = C.a;
    }

    //一般函数
    void Show ()
    {
        cout<<a<<endl;
    }
};

int main()
{
    CExample A(100);
    CExample B = A; // CExample B(A); 也是一样的
     B.Show ();
    return 0;
} 

在这里CExample(const CExample& C) 就是我们自定义的拷贝构造函数。

一.什么是拷贝构造函数

同一个类的对象在内存中有完全相同的结构,如果作为一个整体进行复制或称拷贝是完全可行的。这个拷贝过程只需要拷贝数据成员,而函数成员是共用的(只有一份拷贝)。在建立对象时可用同一类的另一个对象来初始化该对象的存储空间,这时所用的构造函数称为拷贝构造函数。

拷贝构造函数本质上来说也是构造函数。

二.什么情况下使用拷贝构造函数

一般来说有以下三种情况:

class A
{
public:
    A(int i = 0):m_i(i)
    {
        cout<<"A(int) "<<m_i<<endl;
    }
    A(const A &a):m_i(a.m_i)
    {
        cout<<"A(A) "<<m_i<<endl;
    }
    ~A()
    {
        cout<<"~A "<<m_i<<endl;
    }
private:
    int m_i;
};
void fn(A t) //2.将c传递给t的过程,是值传递,此时临时对象形参t是新对象,用c去构造t,调用拷贝构造
{
    cout<<"fn end"<<endl;
    //在退出fn函数时,将临时对象t释放,调用析构函数
}
A test()
{
    A d(40); //调用普通构造A(int)构造对象d
    return d;
    
}
A fnn()
{
    A s(50); //A(int) 50
    return s; //
    
}
void main()
{
    A a(20);  //A(int) 20
    A b = a;  //1.用a初始化b A(A)
    cout<<"fn"<<endl;
    A c(30); //A(int) 30
    fn(c);
    cout<<"test"<<endl;
    c = test(); //临时对象将值赋给c(调用赋值函数)之后,调用析构,析构临时对象
    cout<<"fnn"<<endl;
    A t = fnn(); //临时对象初始化新对象t,是否会调用拷贝构造?--调用了,不过编译器做过优化
    cout<<"main end"<<endl;
}

三.使用拷贝构造函数需要注意什么

拷贝构造函数是构造函数的一个重载形式。

拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。

若未显示定义,系统生成默认的拷贝构造函数。默认的拷贝构造函数对象按内存存储按字节序完成拷贝,称为:位拷贝。

四.深拷贝浅拷贝

4.1 浅拷贝

所谓浅拷贝,指的是在对象复制时,只对对象中的数据成员进行简单的赋值,默认拷贝构造函数执行的也是浅拷贝。大多情况下“浅拷贝”已经能很好地工作了,但是一旦对象存在了动态成员,指针,那么浅拷贝就会出现一些问题。

对于下面函数来说有指针作为数据成员,则用s1对象去构造s2对象的时候,调用默认拷贝构造,用s1中的数据成员指针m_str去初始化s2对象中的数据成员m_str,即是s2.m_str = s1.m_str,那么导致两个对象中的指针指向同一块内存单元,指向的都是构造s1对象时开辟的内存单元,所以在主函数退出时候要析构s2和s1时,将同一段空间释放两次出现内存错误。

class Str
{
public:
    Str(const char *str = "")
    {
        m_str = new char[strlen(str)+1];
        strcpy(m_str,str);
    }
    ~Str()
    {
        delete[]m_str;
    }
    void Print()
    {
        cout<<m_str<<endl;
    }
private:
    char *m_str;
};
void main()
{
    Str s1("pangpang");
    Str s2(s1);
    cout<<sizeof(Str)<<endl;
    s1.Print();
    s2.Print();
}

上述程序的内存布局:

对于指针作为数据成员的类,用s1对象去构造s2对象的时候,调用默认拷贝构造函数时,二者指向同一内存单元,即二者的初始地址相同这里均为0X0002000,当我们构造完以后将要进行析构时,这里将会出现错误:因为析构函数要释放空间,而这里我们的空间对应的是一块空间,当我们析构完s2后:这一块空间的内容已经被delete,而我们还需要析构s1,即:一个内存空间析构了两次,出现内存错误。

为了解决上述问题 我们就需要给s2中的m_str也开辟和s1中的m_str一样大小的空间,所以我们就需要 深拷贝 。

4.2 深拷贝

在“深拷贝”的情况下,对于对象中动态成员,就不能仅仅简单地赋值了,而应该重新动态分配空间,如上面的例子就应该按照如下的方式进行处理:

class Str
{
public:
    Str(const char *str = "")
    {
        m_str = new char[strlen(str)+1];
        strcpy(m_str,str);
    }
    ~Str()
    {
        cout<<"~Str"<<endl;
        delete[]m_str;
    }
    Str(const Str& s)
    {
        cout<<"Str(Str)"<<endl;
        m_str = new char[strlen(s.m_str)+1]; //开辟同样大小的空间
        strcpy(m_str,s.m_str); //将内容拷贝成一样的
    }
    void Print()
    {
        cout<<m_str<<endl;
    }
private:
    char *m_str;
};
void main()
{
    Str s1("pangpang");
    Str s2(s1); //拷贝构造
    s1.Print();
    s2.Print();
}

现在的程序内存布局为:

各自指向一段内存空间,但它们指向的空间具有相同的内容,这就是所谓的“深拷贝”。

到此这篇关于C++实现拷贝构造函数的方法详解的文章就介绍到这了,更多相关C++拷贝构造函数内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯