精华内容
下载资源
问答
  • 拷贝构造

    2018-08-03 16:27:35
    1.什么是拷贝构造 用一个存在的对象去初始化一个新对象时自动调用的一个函数 与一般构造函数的异同:相同点: 1)都是在对象创建的时候自动调用 2)都有类自带的默认构造函数和拷贝构造函数,如果有显式的自己...

    1.什么是拷贝构造

    用一个存在的对象去初始化一个新对象时自动调用的一个函数

    与一般构造函数的异同:
    相同点:

    1)都是在对象创建的时候自动调用

    2)都有类自带的默认构造函数和拷贝构造函数,如果有显式的自己定义的构造函数和拷贝构造函数,则会覆盖默认的

    3)都是用类名作为自己的函数名

    4)构造函数和拷贝构造函数互为重载,看参数的传递

    不同点:

    1)构造函数是在对象创建的时候调用,但拷贝构造函数是新对象在创建的同时用已存在的构造函数来初始化这个对象

    2)默认的构造函数是一个空函数,什么也不执行,但默认的拷贝构造函数执行了内容,赋值了每个非静态成员的值

     

    2.拷贝构造函数的格式

    类名(const 类名 &参数)

    Cperson(const Cperson & a)
    {
    
    }

     

    3.何时调用拷贝构造

    1)类名 新对象(已存在的对象)

    Cperson OldOb;
    
    Cperson NewOb(OldOb);

    2)类名 新对象 = 已存在的对象

    Cperson OldOb;
    
    Cperson NewOb = OldOb;

    3)类名 新对象 = 类名(已存在的对象)

    //右边的是一个临时对象,自己在VS2017中测试,一个单独的临时对象调用的是构造函数

    Cperson OldOb;
    
    Cperson NewOb = Cperson(OldOb);

    4)类名 *新对象 = new 类名(已存在的对象)

    Cperson OldOb;
    
    Cperson *NewOb = new Cperson(OldOb);

    注意:赋值不会调用拷贝构造: 

    Cperson OldOb;
    
    Cperson NewOb;
    
    NewOb = OldOb;

    5)函数参数传递时

    void fun(Cperson ob)
    {
    
    }
    
    int main()
    {
    	Cperson OldOb;
    
    	fun(OldOb);
    
    	system("pause");
    	return 0;
    }

    调用函数fun的时候,将实参对象传递给形参对象,这个过程就相当于是一个给新对象初始化的过程,所以会调用拷贝构造

    6)函数返回一个对象时

    Cperson fun()
    {
    	Cperson a;
    	return a;
    }
    
    int main()
    {
    	Cperson OldOb;
    
    	fun();
    
    	system("pause");
    	return 0;
    }

    返回值的是一个临时对象

     

    4.拷贝构造的功能

    逐个赋值每个非静态成员的值(成员的赋值成为浅赋值),默认的拷贝构造函数是浅拷贝

    同一个类的不同对象,内存排布是一样的,但地址不同

     

    5.深拷贝

    浅拷贝存在的问题:

    先看代码

    #include <iostream>
    using namespace std;
    
    class Cperson
    {
    public:
    	int *a;
    	Cperson()
    	{
    		a = new int[2];
    		a[0] = 1;
    		a[1] = 2;
    	}
    
    	~Cperson()
    	{
    		delete[] a;
    	}
    
    };
    
    
    int main()
    {
    	{
    		Cperson ob1;
    		Cperson ob2 = ob1;
    	}
    
    	system("pause");
    	return 0;
    }

    执行后却报错:

    出现这种错误一般是数组越界、使用了野指针或者分母为零

    那为什么会出现这种错误呢

    首先创建对象ob1时,调用了构造函数,为对象ob1中的成员a开了一个数组空间并赋值,然后用对象ob1去初始化一个新对象ob2的时候,并没有调用构造函数,而调用的是拷贝构造,默认的拷贝构造只是将非静态成员的值简单赋值,所以将对象ob1中的指针成员a的值赋给了对象ob2中的指针成员a,由于a是一个指针变量,两个对象的a指向的是同一块内存地址;执行完后,对象ob1先执行析构函数,释放了对象ob1中指针a指针的内存,此时由于对象ob2中的指针a也是指向的这块内存,所以对象ob2中的指针a沦为了野指针,ob2执行析构函数的时候,尝试再次释放a指针的这块内存,所以出现错误

    修改方法:自己写一个深拷贝

    Cperson(const Cperson &ob)
    {
        this->a = new int[2];
        memcpy(this->a, ob.a, 2 * 4);
    }

    总结:

    1)对于有非静态指针成员的类,应该自己写深拷贝,为每个指针成员新开内存

    2)尽量避免调用拷贝构造,对于函数参数的传递,可以采用引用,或者指针,不调用拷贝构造

     

     

     

    展开全文
  • C++拷贝构造函数详解

    万次阅读 多人点赞 2011-02-23 13:39:00
    什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: int a = 100; int b = a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。 下面看一个类对象...

    一. 什么是拷贝构造函数

    首先对于普通类型的对象来说,它们之间的复制是很简单的,例如:


    而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。
    下面看一个类对象拷贝的简单例子。

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

    下面举例说明拷贝构造函数的工作过程。


    CExample(const CExample& C) 就是我们自定义的拷贝构造函数。可见,拷贝构造函数是一种特殊的构造函数,函数的名称必须和类名称一致,它必须的一个参数是本类型的一个引用变量


    二. 拷贝构造函数的调用时机

    在C++中,下面三种对象需要调用拷贝构造函数!
    1. 对象以值传递的方式传入函数参数


    调用g_Fun()时,会产生以下几个重要步骤:
    (1).test对象传入形参时,会先会产生一个临时变量,就叫 C 吧。
    (2).然后调用拷贝构造函数把test的值给C。 整个这两个步骤有点像:CExample C(test);
    (3).等g_Fun()执行完后, 析构掉 C 对象。

    2. 对象以值传递的方式从函数返回


    当g_Fun()函数执行到return时,会产生以下几个重要步骤:
    (1). 先会产生一个临时变量,就叫XXXX吧。
    (2). 然后调用拷贝构造函数把temp的值给XXXX。整个这两个步骤有点像:CExample XXXX(temp);
    (3). 在函数执行到最后先析构temp局部变量。
    (4). 等g_Fun()执行完后再析构掉XXXX对象。

    3. 对象需要通过另外一个对象进行初始化;

    后两句都会调用拷贝构造函数。


    三. 浅拷贝和深拷贝

    1. 默认拷贝构造函数

        很多时候在我们都不知道拷贝构造函数的情况下,传递对象给函数参数或者函数返回对象都能很好的进行,这是因为编译器会给我们自动产生一个拷贝构造函数,这就是“默认拷贝构造函数”,这个构造函数很简单,仅仅使用“老对象”的数据成员的值对“新对象”的数据成员一一进行赋值,它一般具有以下形式:

     
        当然,以上代码不用我们编写,编译器会为我们自动生成。但是如果认为这样就可以解决对象
    的复制问题,那就错了,让我们来考虑以下一段代码:

      这段代码对前面的类,加入了一个静态成员,目的是进行计数。在主函数中,首先创建对象rect1,输出此时的对象个数,然后使用rect1复制出对象rect2,再输出此时的对象个数,按照理解,此时应该有两个对象存在,但实际程序运行时,输出的都是1,反应出只有1个对象。此外,在销毁对象时,由于会调用销毁两个对象,类的析构函数会调用两次,此时的计数器将变为负数。

    说白了,就是拷贝构造函数没有处理静态数据成员。

    出现这些问题最根本就在于在复制对象时,计数器没有递增,我们重新编写拷贝构造函数,如下

    2. 浅拷贝

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

        在这段代码运行结束之前,会出现一个运行错误。原因就在于在进行对象复制时,对于动态分配的内容没有进行正确的操作。我们来分析一下:

        在运行定义rect1对象后,由于在构造函数中有一个动态分配的语句,因此执行后的内存情况大致如下:

     

     

        在使用rect1复制rect2时,由于执行的是浅拷贝,只是将成员的值进行赋值,这时 rect1.p = rect2.p,也即这两个指针指向了堆里的同一个空间,如下图所示:

     

    当然,这不是我们所期望的结果,在销毁对象时,两个对象的析构函数将对同一个内存空间释放两,这就是错误出现的原因。我们需要的不是两个p有相同的值,而是两个p指向的空间有相同的值,解决办法就是使用“深拷贝”。


    3. 深拷贝

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

    此时,在完成对象的复制后,内存的一个大致情况如下:

     

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


    3. 防止默认拷贝发生

        通过对对象复制的分析,我们发现对象的复制大多在进行“值传递”时发生,这里有一个小技巧可以防止按值传递——声明一个私有拷贝构造函数。甚至不必去定义这个拷贝构造函数,这样因为拷贝构造函数是私有的,如果用户试图按值传递或函数返回该类对象,将得到一个编译错误,从而可以避免按值传递或返回对象。

    四. 拷贝构造函数的几个细节

    1. 拷贝构造函数里能调用private成员变量吗?
    解答:
    这个问题是在网上见的,当时一下子有点晕。其时从名子我们就知道拷贝构造函数其时就是
    一个特殊的构造函数,操作的还是自己类的成员变量,所以不受private的限制。


    2. 以下函数哪个是拷贝构造函数,为什么?


    解答:对于一个类X, 如果一个构造函数的第一个参数是下列之一:
    a) X&
    b) const X&
    c) volatile X&
    d) const volatile X&
    且没有其他参数或其他参数都有默认值,那么这个函数是拷贝构造函数.


    3. 一个类中可以存在多于一个的拷贝构造函数吗?
    解答:
    类中可以存在超过一个拷贝构造函数。


    注意,如果一个类中只存在一个参数为 X& 的拷贝构造函数,那么就不能使用const X或volatile X的
    对象实行拷贝初始化.


    如果一个类中没有定义拷贝构造函数,那么编译器会自动产生一个默认的拷贝构造函数。
    这个默认的参数可能为 X::X(const X&)X::X(X&),由编译器根据上下文决定选择哪一个。

    展开全文
  • TClass C(A); // 这个时候会调用一次拷贝构造
  • 拷贝构造函数,默认拷贝构造函数 1.c++的默认拷贝构造函数,从深度拷贝和浅拷贝说起 c++类的默认拷贝构造函数的弊端 c++类的中有两个特殊的构造函数,(1)无参构造函数,(2)拷贝构造函数。它们的特殊之处在于: (1)...

    拷贝构造函数,默认拷贝构造函数
    1.c++的默认拷贝构造函数,从深度拷贝和浅拷贝说起

    1. c++类的默认拷贝构造函数的弊端
      c++类的中有两个特殊的构造函数,(1)无参构造函数,(2)拷贝构造函数。它们的特殊之处在于:
      (1)当类中没有定义任何构造函数时,编译器会默认提供一个无参构造函数且其函数体为空;
      (2)当类中没有定义拷贝构造函数时,编译器会默认提供一个拷贝构造函数,进行成员变量之间的拷贝。(这个拷贝操作是浅拷贝)
      class TestCls{
      public:
      int a;
      int *p;

    public:
    TestCls() //无参构造函数
    {
    std::cout<<“TestCls()”<<std::endl;
    p = new int;
    }

    ~TestCls()     //析构函数
    {
        delete p;   
        std::cout<<"~TestCls()"<<std::endl;
    }
    

    };
    int main(void)
    {
    TestCls t;
    return 0;
    }
    编译运行确实不会出错:

    类在我们没有定义拷贝构造函数的时候,会默认定义默认拷贝构造函数,也就是说可以直接用同类型的类间可以相互赋值、初始化:
    int main(void)
    { TestCls t1; TestCls t2 = t1; //效果等同于TestCls t2(t1); return 0; }
    这样结果就会出错。

    原因就在于,默认的拷贝构造函数实现的是浅拷贝。
    2.深度拷贝和浅拷贝
    深度拷贝和浅拷贝在c语言中就经常遇到的了,在这里我简单描述。
    一般的赋值操作是深度拷贝:

    //深度拷贝
    int a = 5;
    int b = a;
    简单的指针指向,则是浅拷贝:
    //浅拷贝
    int a = 8;
    int *p;
    p = &a;

    char* str1 = “HelloWorld”;
    char* str2 = str1;
    将上面的浅拷贝改为深度拷贝后:
    //深度拷贝
    int a = 8;
    int *p = new int;
    *p = a;

    char* str1 = “HelloWorld”;
    int len = strlen(str1);
    char *str2 = new char[len];
    memcpy(str2, str1, len);
    能看得出深度拷贝和浅拷贝的差异。拷贝者和被拷贝者若是同一个地址,则为浅拷贝,反之为深拷贝。 
    以字符串拷贝为例,浅拷贝后,str1和str2同指向0x123456,不管哪一个指针,对该空间内容的修改都会影响另一个指针。

    深拷贝后,str1和str2指向不同的内存空间,各自的空间的内容一样。因为空间不同,所以不管哪一个指针,对该空间内容的修改都不会影响另一个指针。

    1. 解决默认拷贝构造函数的弊端
      类的默认拷贝构造函数只会用被拷贝类的成员的值为拷贝类简单初始化,也就是说二者的p指针指向的内存空间是一致的。以前面TestCls可以知道,编译器为我们默认定义的拷贝构造函数为:
      TestCls(const TestCls& testCls)
      { a = testCls.a; p = testCls.p; //两个类的p指针指向的地址一致。 }
      main函数将要退出时,拷贝类t2的析构函数先得到执行,它把自身p指向的堆空间释放了;接下来,t1的析构函数得到调用,被拷贝类t1的析构函数得到调用,它同样要去析构自身的p指向指向的堆空间,但是该空间和t2类中p指向的空间一样,造成重复释放,程序运行崩溃。
      解决办法就是自定义拷贝构造函数;
      class TestCls{
      public:
      int a;
      int *p;

    public:
    TestCls()
    {
    std::cout<<“TestCls()”<<std::endl;
    p = new int;
    }

    TestCls(const TestCls& testCls)
    {
        cout<<"TestCls(const TestCls& testCls)"<endl;
        a = testCls.a;
        //p = testCls.p;
        p = new int;
        *p = *(testCls.p);      //为拷贝类的p指针分配空间,实现深度拷贝
    }
    
    ~TestCls()
    {
        delete p;   
      cout<<"~TestCls()"<<endl;
    }
    

    };

    int main(void)
    {
    TestCls t1;
    TestCls t2 = t1;
    return 0;
    }

    展开全文
  • 一、默认拷贝构造函数、浅拷贝 当对一个已知对象进行拷贝时,编译系统会自动调用一种构造函数 —— 拷贝构造函数,如果用户未定义拷贝构造函数,则会调用默认拷贝构造函数。 #include <iostream> using ...

    一、默认拷贝构造函数、浅拷贝

            当对一个已知对象进行拷贝时,编译系统会自动调用一种构造函数 —— 拷贝构造函数,如果用户未定义拷贝构造函数,则会调用默认拷贝构造函数

    #include <iostream>  
    using namespace std;
     
    class Student
    {
    private:
        int num;
        char *name;   //此处类中包含指针
    public:
        Student();
        ~Student();
    };
     
    Student::Student()
    {
        name = new char(20);
        cout << "Student" << endl;
     
    }
    Student::~Student()
    {
        cout << "~Student " << (int)name << endl;
        delete name;
        name = NULL;
    }
     
    int main()
    {
        {// 花括号让s1和s2变成局部对象,方便测试
            Student s1;
            Student s2(s1);// 复制对象
        }
        system("pause");
        return 0;
    }

            执行结果:调用一次构造函数,调用两次析构函数,两个对象的指针成员所指同一块内存,这会导致什么问题呢?name指针被分配一次内存,但是程序结束时该内存却被释放了两次,会导致崩溃!

            由于编译系统在我们没有自己定义拷贝构造函数时,会在拷贝对象时调用默认拷贝构造函数,进行的是浅拷贝!即对指针name拷贝后会出现两个指针指向同一个内存空间。

    二、自定义拷贝构造函数、深拷贝

            所以,在对含有指针成员的对象进行拷贝时,必须要自己定义拷贝构造函数,使拷贝后的对象指针成员有自己的内存空间,即进行深拷贝,这样就避免了内存泄漏发生。

            //自己定义构造函数,进行深拷贝

    Student::Student(const Student &s)
    {
        name = new char(20);
        memcpy(name, s.name, strlen(s.name));  
        cout << "copy Student" << endl;
    }

            执行结果:调用一次构造函数,一次自定义拷贝构造函数,两次析构函数。两个对象的指针成员所指内存不同。

    三、浅拷贝、深拷贝

    1、浅拷贝只是对指针的拷贝,拷贝后两个指针指向同一个内存空间。

    2、深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针。

    四、浅拷贝带来的问题

    1、两个对象的指针成员可能指向相同的内存相互影响

    2、对其中一个指针进行释放操作或销毁析构,将导致另一个指针成为 “悬空指针”。

     

    参考链接

    https://blog.csdn.net/chen1234520nnn/article/details/83338990

    展开全文
  • 拷贝构造函数

    千次阅读 2019-09-08 09:52:47
    拷贝构造函数即系统自带的拷贝构造函数,当程序将一个已经定义的对象数据给另一个对象作为初始值时,并且程序为自定义拷贝构造函数,系统就会自动调用默认拷贝构造函数. 形式: 自定义拷贝构造函数(深拷贝) Human...
  • 有时候我们习惯性的认为在子类拷贝构造的时候会自动的调用父类的拷贝构造,这种观点来自于子类构造时会自动调用父类的构造函数(父类先于子类构造),子类析构的时候会自动调用父类的析构函数(父类后于子类析构)。...
  • 编译器永远不会把模板构造函数视为构造函数,即使客户没有自己定义拷贝构造函数,编译器也会生成一个默认的拷贝构造函数,这种情况同样存在于拷贝赋值函数和模板拷贝赋值函数。请看下面的例子:...
  • c++的默认拷贝构造函数,从深度拷贝和浅拷贝说起

    万次阅读 多人点赞 2017-07-24 19:44:10
    1. c++类的默认拷贝构造函数的弊端c++类的中有两个特殊的构造函数,(1)无参构造函数,(2)拷贝构造函数。它们的特殊之处在于: (1)当类中没有定义任何构造函数时,编译器会默认提供一个无参构造函数且其函数体为空;...
  • 构造函数与拷贝构造函数

    千次阅读 多人点赞 2019-04-03 09:07:15
    拷贝构造函数和构造函数不能分开说,他们都是初始化对象的一种方法。但是我们这里用构造函数辅助说明拷贝构造函数,主要说说拷贝构造函数的声明,用途和使用注意事项。 众所周知,构造函数是一个初始化类对象的函数...
  • 拷贝构造与拷贝赋值

    千次阅读 2017-10-18 19:56:55
    代码:Sales_data类中的拷贝构造函数和拷贝赋值运算符定义如下://Sales_data类的拷贝构造函数定义 Sales_data::Sales_data(const Sales_data &orig): bookNo(org.bookNo), //使用string的拷贝构造函数
  • 1.什么是拷贝构造函数: CA(const CA& C)就是我们自定义的拷贝构造函数。可见,拷贝构造函数是一种特殊的构造函数,函数的名称必须和类名称一致,它的唯一的一个参数是本类型的一个引用变量,该参数是const类型...
  • C++拷贝构造、赋值构造详解

    万次阅读 多人点赞 2018-06-02 00:09:55
    一、前言 写一个用到指针的程序时,被拷贝、赋值、析构函数坑了一波,网上查相关博客,发现关于拷贝、赋值构造... //拷贝构造函数 A (const A&amp; a); //拷贝构造函数 A&amp; operator= (const A&am...
  • 拷贝构造又称为复制构造,是一种特殊的构造函数,它是使用一个现有的对象来构造一个新的对象,只有一个引用型的参数(对象本身)。 类名(类& ) { } 拷贝构造的参数应该加const保护,但编译器并没有强制限制。 ...
  • 我们知道C++ 编写程序的一个特点就是需要程序员...C++编写类时,如果类中包含指针成员,就需要特别小心拷贝构造函数的编写,因为很容易造成内存泄漏。例如以下情况: 浅拷贝造成内存泄漏的例子 #include <iost...
  • 拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。拷贝构造函数常用于: 通过使用另一个同类型的对象来初始化新创建的对象; 复制对象把它作为参数传递给...
  • 一、拷贝构造  如果一个构造函数的第一个参数是自身类类型的引用,且任何额外参数都没有默认值,则此构造函数是拷贝构造函数。(《C++Primer,第五版》) class Foo { public : Foo(); Foo(const Foo&); //...
  • 拷贝构造和拷贝赋值

    千次阅读 2018-03-28 01:27:10
    注意指针类型成员变量的深拷贝问题拷贝构造属于定义,并赋值拷贝赋值属于已经定义,只是赋值。拷贝构造的深拷贝,因为如果提供了拷贝构造函数,则构造该对象时使用的是拷贝构造函数。 在拷贝构造函数中只需要: ...
  • 自定义拷贝构造函数 类名::类名(const 类名 &对象名) {  拷贝构造函数的函数体 } 利用下述语句调用拷贝构造函数 Rectangle p2(p1); #include using namespace std; class Rectangle { public:  Rectangle...
  • c++拷贝构造函数

    千次阅读 多人点赞 2019-06-28 16:22:40
    什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: int a = 100; int b = a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。 下面看一个类对象...
  • C++拷贝构造函数与拷贝赋值运算符

    千次阅读 2019-04-20 21:44:45
    拷贝构造函数 拷贝构造函数定义了当同类型的另一个对象初始化本对象时做什么,如果一个构造函数的第一个参数是自身类类型的引用,且任何额外参数都有默认值,则此构造函数是拷贝构造函数。拷贝构造函数的参数类型...
  • 如果一个类需要自己定义析构函数,往往需要自己定义拷贝构造和拷贝赋值,系统默认合成的拷贝构造和拷贝赋值知识简单的拷贝指针成员,意味着可能会造成多个指针指向同一个内存。class A{private: B* m_data;}A a1;A ...
  • 拷贝构造函数和拷贝赋值函数

    千次阅读 2018-03-12 23:40:01
    拷贝构造函数和拷贝赋值函数的区别 拷贝构造函数是针对一个未存在的对象进行初始化;拷贝赋值函数是针对已存在的对象进行初始化。 A a; A b = a; //拷贝构造 A c; b = c; //拷贝赋值 怎么避免一个对象给...
  • 何为拷贝构造函数? 一般一个构造函数的参数是自身类类型的const引用,则这个构造函数就是拷贝构造函数。 拷贝构造函数是被用来初始化 非引用类 类型参数, 参数必须是引用类型。 如: class MyString {  ...
  • 拷贝构造(浅拷贝,深拷贝)

    千次阅读 2018-12-12 20:08:45
    空类中默认的函数有 默认的构造函数,析构,拷贝构造(浅拷贝),operator= 1. 什么是拷贝构造? 第一个参数 是当前这个类的 const类型的引用 的构造函数 2. 干什么用的? 复制一个对象 3. 什么时候执行? 用一个...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 293,152
精华内容 117,260
关键字:

拷贝构造