精华内容
下载资源
问答
  • 复制构造函数

    千次阅读 多人点赞 2018-09-03 11:11:35
    简述 复制构造函数是一种特殊构造函数,在生成一个实例时,一般会同时生成一个默认的复制构造函数,...每个类都必须一个复制构造函数。如果程序员没有显式地定义一个复制构造函数,C++编译器会自动生成一个缺省...

    简述

    • 复制构造函数是一种特殊构造函数,在生成一个实例时,一般会同时生成一个默认的复制构造函数,复制构造函数完成一些基于同一类的其他对象的构建及初始化工作。

    特点

    • 复制构造函数名与类名同名,因为它是一种构造函数,并且函数不指定返回类型。

    • 该函数只有一个参数,并且是某个对象的引用

    • 每个类都必须有一个复制构造函数。如果程序员没有显式地定义一个复制构造函数,C++编译器会自动生成一个缺省的复制构造函数。

    • 复制构造函数需要考虑深拷贝和浅拷贝的问题,默认构造函数只进行浅拷贝,当我们的类私有数据成员中含有指着类型时,需要进行深拷贝,即显式地定义复制构造函数

    #include<iostream>
    
    using namespace std;
    
    class A {
    public:
        A(int val) :a(val) {
            p = new int(a);
        }
        A(const A& it) {
            a = it.a;
            delete p;
            p = new int(a);
            cout << it.p << endl;  //0051C0B8
            cout << p << endl;     //0051C0E8
        }
        int get() {
            return *p;
        }
    private:
        int a;
        int *p;
    };
    
    int main(int argc, char* argv[]) {
        A A1(10);
        A A2(A1);
        cout << A2.get() << endl;  //10
        getchar();
        return 0;
    }

    复制构造函数和赋值运算符的区别

    • 复制构造函数生成新的类对象,而赋值运算符不能。

    • 当类中有指针类型的成员变量时,一定要重写复制构造函数和赋值运算符,不能使用默认的。

    • 当进行一个类的实例初始化时,也就是构造时,调用的是构造函数,但如果用其他实例来初始化,则调用的是复制构造函数,非初始化时这个实例进行赋值调用的是赋值运算符。(重要!!!)

    #include<iostream>
    
    using namespace std;
    
    class A {
    public:
        A(int val) :a(val) {
            p = new int(a);
        }
        A(const A& it) {
            cout << "复制构造函数" << endl;
            a = it.a;
            delete p;
            p = new int(a);
            cout << it.p << endl;  
            cout << p << endl;     
        }
        A& operator=(const A& it) {
            cout << "赋值运算符" << endl;
            a = it.a;
            delete p;
            p = new int(a);
            cout << it.p << endl;  
            cout << p << endl;    
            return *this;
        }
        int get() {
            return *p;
        }
    private:
        int a;
        int *p;
    };
    
    int main(int argc, char* argv[]) {
        A A1(10);
        A A3(30);
        A A2 = A1;
        A2 = A3;
        cout << A2.get() << endl; 
        getchar();
        return 0;
    }

    这里写图片描述

    扩展:空类默认产生哪些成员函数

    • 默认构造函数

    • 复制构造函数

    • 析构函数

    • 赋值运算符重载函数

    • 取址运算符重载函数

    • const取址运算符重载函数

    class A {
    public:
        A();
        ~A(){}
        A(const A&);
        A& operator=(const A&);
        A* operator&();
        const A* operator&() const;
    };
    展开全文
  • 什么复制构造函数复制构造函数是一种特殊的构造函数,具有一般构造...那么复制构造函数一般在什么情况下被调用呢,三种情况: (1)当类的一个对象去初始化该类的另一个对象的时候 例: int main() ...

    什么是复制构造函数:

            复制构造函数是一种特殊的构造函数,具有一般构造函数的所有特性 ,它的形参是本类的对象的引用,比如(类名   对象名)。它的作用是使用一个已经存在的对象(此对象由复制构造函数的参数决定),去初始化同类的一个新对象。那么复制构造函数一般在什么情况下被调用呢,有三种情况:

    (1)当用类的一个对象去初始化该类的另一个对象的时候

    :   int  main()

              {

                        Point  a(1,2);              // 调用类的构造函数(Point类)

                        Point  b(a);                 // 用已存在的对象a初始化新对象b,复制构造函数被调用

                        Point c=a;                  // 用已存在的对象a初始化新对象c,复制构造函数被调用

                        return 0;

               }

    (2)如果函数的形参是类的对象,调用此函数的时候,进行形参和实参相结合时,复制构造函数被调用

    例:    void f(Point  p)

             {

                   cout<<p.getX()<<endl;

             }

             int main()

             {

                    Point  a(1,2);

                    f(a);                                         // 函数的形参为类的对象,当调用函数时,实参与形参结合,复制构造函数被调用

                    return 0;

              }

                    注意:只有把对象用值传递的时候,才会调用复制构造函数,如果传递引用,则不会调用复制构造函数。

    (3)如果函数的返回值是类的一个对象,函数执行完成返回调用者时,复制构造函数被调用

    :         Point  g()

                 {

                           Point  a(1,2);

                           return a;                            // 函数的返回值是类的对象a,返回函数值时,复制构造函数被调用

                 }

                int main()

                {

                           Point  b;

                           b=g();

                           return  0;

                 }

                  注意:这种情况下,表面上函数g将a返回给了主函数,但是a是g()的局部对象,离开建立他的函数g以后a就不存在了,不可能在返回给主函数后继续生存,所以在处理这种情况的时候编译器系统会在主函数中创建一个无名的临时对象,该临时对象的生存期只在函数调用所处的表达式中,也就是表达式 b=g() 中。执行语句“ return a ”时,实际上是调用复制构造将a的值复制到临时对象中,所以在此调用了复制构造函数。函数g运行结束时对象a消失,但临时对象会存在于表达式“ b=g()”中。计算完这个表达式后,临时对象的任务也就完成了,改临时对象就会自动消失。

            以上便是复制构造函数经常被调用的三种情况。下面我写一下类Point,便于大家参考。

    class  Point

    {

       public:

                Point (int xx=0, int yy=0)                 // 构造函数,带有形参

                {                 

                              x=xx;   y=yy;           

                }

                Point (Point &p);                           // 复制构造函数

                int getX() {   return x;   }

                ..........

       private:

                 int x , y;

    };

    Point::Point(Point  &p)                 // 复制构造函数实现

                 x=p.x;

                 y=p.y;

    }

    展开全文
  • 类的赋值构造函数和复制构造函数

    千次阅读 2016-10-31 22:41:49
    整体的说一下,复制构造函数和赋值构造函数的相同点是: 赋值运算符和复制构造函数都是已存在的B对象来创建另一个对象A; 最大的不同在于:赋值构造函数处理两个已对象,即赋值前B应该是存在的;复制构造函数是...

    C++的初学者经常会对复制构造函数一知半解,我曾经对复制构造函数和赋值函数就很是迷茫。闲来无事,整理一下,一个对象的复制构造函数和赋值构造函数。整体的说一下,复制构造函数和赋值构造函数的相同点是: 赋值运算符和复制构造函数都是用已存在的B对象来创建另一个对象A;
    最大的不同在于:赋值构造函数处理两个已有对象,即赋值前B应该是存在的;复制构造函数是生成一个全新的对象,即调用复制构造函数之前A不存在。

    - 类

    首先,介绍一下类:类是数据以及用于操纵该数据的方法(函数)的集合,是逻辑上相关函数与数据的封装。它是对所要处理问题的抽象描述,它把数据(事物的属性)和函数(事物的行为/操纵)封装为一个整体。
    类的定义格式如下:

    class 类名{
    private//私有数据和函数
    protect:
    //保护数据和函数
    public//公有数据和函数
    }

    C++中面向对象的思想是对对象的属性(成员变量)进行操作,应该通过对象的方法(成员函数)来进行,对象的方法是对象和外部的接口。
    这里顺便说一句成员函数的定义通常的格式是:

    范围值类型 类名::函数名(参数表)
    {
    //函数体
    }

    很多基础比较差的程序员,“::”符号不知道是什么意思(虽然知道也没什么用),只知道怎么用!运算符“::”成为作用域解析运算符,它指出该函数是属于哪一类的成员函数。当然也可以在类的定义中直接定义函数。所以有的时候也不用“::”符号.

    对象即类的实例。创建类的对象可以常用的两种方法:
    1、直接创建对象,比如CObject类的一个对象 CObject object;(注意这里的object是一个临时对象)
    2、采用动态创建类的对象的方法,当然遍历同样也可以动态创建。

    - 复制构造函数

    上面说到了类,也说到了对象的创建,那么同一个类的对象在内存中有完全相同的结构,如果作为一个整体进行复制是完全可行的。这个复制的过程只需要把数据成员复制过来即可,而函数成员是可以共用的,同一个类的任何对象都可以共用这个类的函数成员。
    在建立对象时可以用同一类的另一个对象来初始化该对象,这时所用的构造函数成为复制构造函数。像X::X(X&),这种形式,且只有一个参数——同类的对象,采用的是引用的方式。不能用X::X(X)这种形式的构造函数,如果把一个真实的类的对象作为参数传递到复制构造函数,会引起无穷的递归。那很多人有不解,平常我创建类的对象的时候也没有写复制构造函数呀,为什么也没有报错呢?原因是如果没有定义的话,那么编译器生成默认复制构造函数;如果定义了地自己的复制构造函数,则默认的复制构造函数就不存在了。(这一点与析构函数不同,即使自己定义了析构函数,默认的析构函数仍然存在)
    复制构造函数在以下3中情况下会被调用:

    1. 当用一个对象去初始化同类的另一个对象时。
    CObject o2(o1);
    //
    CObject o2=o1;
    1. 如果某函数有一个形参是类A的对象,那么该函数被调用时,类A的复制构造函数将被调用。
    void Fun(CObject object)
    {
        object.a=1;
    }
    CObject object;
    Fun(object);
    //CObject 的复制构造函数被调用,生成形参,在内存新建一个局部对象,并把实参复制到新的对象中。
    1. 如果函数的返回值是类CObject的对象,则函数返回时,CObject的复制构造函数被调用。理由也是建立一个临时对象,再返回调用者。
    CObject Fun()
    {
        CObject object;
        return object; //在此处调用了CObject(object)
    }
    int main()
    {
        CObject object; //此处是一个局部对象,也是一个临时对象
        object = Fun(); 
        return 0;
    }

    有人可能会问,为什么不直接用要返回的局部对象呢?因为局部对象在离开建立它的函数时就消亡了,不可能在返回调用函数后继续生存。所以编译系统会在调用函数的表达式中创建一个无名临时对象,该临时对象的生存周期只在函数调用处的表达式中。所谓返回对象,实际上就是调用复制构造函数把该对象的值复制到临时对象中。

    -赋值构造函数

    首先看一段代码:

    int main()
    {
        CObject theObjectOne;
        theObjectOne.Init(100);
    
        CObject theObjectTwo;
        theObjectTwo.Init(200);
    
        theObjectTwo = theObjectOne;
        //此操作是对象赋值操作,更深一步的操作时将被复制对象theObjectTwo对象原有的内容清除,并用theObjectOne对象里的内容填充。
        return 0;
    }

    “=”就是讲一个对象里的内容到另一个对象中去,这其中涉及到对象原有内容的丢弃和新内容的复制。由于对象内容包含指针,将造成不良的后果:指针的值被丢弃了(指针内容丢失了也就是说指针地址丢失了,但是改地址中所存储的内容没有丢失,但指针指向的内容并未释放。指针的值被复制了,但是指针所指内容并未复制,这就要出大事儿了)。所以如果类的对象中有指针的话,此处的“=”绝对不能是我们平常理解的简简单单的等于号,这个“=”必须重载,而这个“=”的重载函数就是我们要讨论的赋值构造函数。

    我们再来理解两个概念:值拷贝和位拷贝,位拷贝拷贝的是地址;值拷贝拷贝的是内容。理解了这两个概念我们再看一段代码:
    定义一个string类,但是不实现其他的成员函数

    Class String
    {
    public:
               String(const char *ch = NULL); //默认构造函数
               String(const String &str); //复制构造函数
               ~String();
               String &operator=(const String &str);//赋值构造函数
     privat:
                char *m_data;
    }
    
    int main()
    {
        String strA;
        strA.m_data=L"Windows";
        String strB;
        strB.m_data=L"Linux";
    
        strB.m_data = strA.m_data;
    }

    如果“=”未重写赋值构造函数的话,将strA赋给strB;则编译器会默认进行位拷贝,即strB.m_data = strA.m_data;
    则strA.m_data和strB.m_data都指向了同一块区域,虽然strA.m_data指向的内容会改变为“Linux”,但是会出现这样的问题:
    (1)strB.m_data原来指向的内存区域未释放,造成内存泄露。
    (2)strB.m_data和strA.m_data指向同一块区域,任何一方改变都会影响另一方。
    (3)当对象被析构时,strA.m_data被释放两次。

    如果“=”重写了复制构造函数后,strB.m_data = strA.m_data;进行的是值拷贝,会将strA.m_data的内容赋给strB.m_data,strB.m_data还是指向原来的内存区域,但是其内容改变。

    所以在我理解起来,赋值构造函数其实就是对“=”的重载。缺省的赋值构造函数采用的是“位拷贝”而非“值拷贝”的方式实现。如果类中含有指针变量,那么赋值构造函数如果不重载的话肯定会出错。理解到这里,我们再回过头看一下复制构造函数,其实也是一样的道理,缺省的复制构造函数采用的也是“位拷贝”的方式实现,所以如果类中含有指针变量的话我们也需要重写复制构造函数。
    总而言之一句话,什么把你弄的这么头疼来看这篇文章,归根到底就是——指针。

    最后附上一段不错的理解复制构造函数和赋值构造函数的代码:

    #include <iostream>
    #include <cstring>
    using namespace std;
    
    class String  
    {
        public:
            String(const char *str);
            String(const String &other);
            String & operator=(const String &other);
            ~String(void); 
        private:
            char *m_data;
    };
    
    String::String(const char *str)
    {
        cout << "自定义构造函数" << endl;
        if (str == NULL)
        {
            m_data = new char[1];
            *m_data = '\0';
        }
        else
        {
            int length = strlen(str);
            m_data = new char[length + 1];
            strcpy(m_data, str);
        }
    }
    
    String::String(const String &other)
    {
        cout << "自定义复制构造函数" << endl;
        int length = strlen(other.m_data);
        m_data = new char[length + 1];
        strcpy(m_data, other.m_data);
    }
    
    String & String::operator=(const String &other)
    {
        cout << "自定义赋值函数" << endl; 
    
        if (this == &other)
        {
            return *this;
        }
        else
        {
            delete [] m_data;
            int length = strlen(other.m_data);
            m_data = new char[length + 1];
            strcpy(m_data, other.m_data);
            return *this;
        }
    }
    
    String::~String(void)
    {
        cout << "自定义析构函数" << endl; 
        delete [] m_data;
    }
    int main()
    {
        cout << "a(\"abc\")" << endl;
        String a("abc");
    
        cout << "b(\"cde\")" << endl;
        String b("cde");
    
        cout << " d = a" << endl;
        String d = a;
    
        cout << "c(b)" << endl;
        String c(b);
    
        cout << "c = a" << endl;
        c = a;
    
        cout << endl;

    执行结果

    a(“abc”)
    执行自定义构造函数
    b(“ced”)
    执行自定义构造函数
    d=a
    执行自定义复制构造函数
    c(b)
    执行自定义复制构造函数
    c=a
    执行自定义赋值函数

    执行自定义析构函数
    执行自定义析构函数
    执行自定义析构函数
    执行自定义析构函数

    说明几点

    1. 赋值函数中,上来比较 this == &other 是很必要的,因为防止自复制,这是很危险的,因为下面有delete []m_data,如果提前把m_data给释放了,指针已成野指针,再赋值就错了

    2. 赋值函数中,接着要释放掉m_data,否则就没机会了(下边又有新指向了)

    3. 拷贝构造函数是对象被创建时调用,赋值函数只能被已经存在了的对象调用

      注意:String a(“hello”); String b(“world”); 调用自定义构造函数

           String c=a;调用拷贝构造函数,因为c一开始不存在,最好写成String c(a);
      
    展开全文
  • 构造函数用来初始化对象的,复制构造函数是把一个已知的对象复制给新的对象,(2者都是对象)。 浅复制构造函数只复制指针(换句话说就是2个对象的地址一样), 深复制构造函数定义内new了一个新地址,因此2个对象...
    构造函数用来初始化对象的,复制构造函数是把一个已知的对象复制给新的对象,(2者都是对象)。
    复制构造函数只复制指针(换句话说就是2个对象的地址一样),例如
    class A
    {
    pubic:
      A(){x = new int; *x =  8;}
      A(const A &a)
      {
       x = a.x   //浅层复制构造函数
      }
      ~A(){delete x; x = NULL;}
    private:
    int *x;
    }
    复制构造函数定义内new了一个新地址,因此2个对象的地址不一样,析构2个对象的时候不会象浅复制构造函数那样重复析构一个地址了。例如
    class A
    {
    pubic:
      A(){x = new int; *x =  8;}
      A(const A &a)
      {
       x = new int;    //注意区分x,这个x是复制的对象中的指针x
       *x = *(a.x)   //浅深层复制构造函数
      }
      ~A(){delete x; x = NULL;}
    private:
    int *x;
    }
     
    重点是区分概念,和区分x,要不很容易混乱
    另外补加一个小概念,对于高大上的“级连”,比如说cout语句能实现级连,就是指提取运算符"<<"能连续使用,例如cout<<x<<y<<z;这里的"<<"用了三次
    展开全文
  • 复制构造函数与拷贝构造函数

    千次阅读 2014-09-16 11:39:03
    对于我来说,在写代码的时候能得上复制构造函数的机会并不多,不过这并不说明复制构造函数什么用,其实复制构造函数能解决一些我们常常会忽略的问题。  为了说明复制构造函数作用,我先说
  • C++复制构造函数

    千次阅读 2018-05-09 23:17:09
    C ++里的类默认构造函数,自己定义的构造函数,允许通过类构造函数实现类的类型的隐式转换或者显示转换(构造函数前带explicit关键字),比如如下代码Jungle定义了一个类A,定义了两个构造函数: using namespace...
  • 什么复制构造函数

    千次阅读 2016-03-14 13:58:06
    复制构造函数又称为拷贝构造函数,是一种特殊的构造函数,它由编译器调用来完成一些基于同一类的其他对象的构建及初始化。它存在唯一一个参数是不可变的。这个函数经常在函数调用期间于用户定义类型的值传递及返回。...
  •  也许很多C++的初学者都知道什么是构造函数,但是对复制...对于我来说,在写代码的时候能得上复制构造函数的机会并不多,不过这并不说明复制构造函数什么用,其实复制构造函数能解决一些我们常常会忽略的问题。
  • 什么复制构造函数复制构造函数是一个成员函数,它使用同一个类的另一个对象初始化一个对象。函数原型如下: ClassName(const ClassName &old_obj); 下面是一个复制构造函数的简单示例: #include <...
  • 假设Person是一个类,复制构造函数的调用会在以下几种情况下发生: 1、对象在创建时使用其他的对象初始化 Person p(q); //此时复制构造函数被用来创建实例p Person p = q; //此时复制构造函数被用来在定义...
  • 构造函数和复制构造函数 转载自:http://hi.baidu.com/myzjdx/blog/item/db36a6dd58faf4df8d1029b3.html  构造函数、复制构造函数和赋值操作符在生成对象和对象之间的复制时用到。如果类中没有显式定义这三种...
  • ① 类内自定义构造函数和自定义复制构造函数   根据C++标准定义,如果程序已定义构造函数,默认情况下编译器就不再隐含生成默认构造函数。注意,这里的“构造函数”包括复制构造函数(因为复制构造函数也是构造...
  • 浅析复制构造函数

    2013-06-05 18:01:08
    复制构造函数  复制构造函数是一种特殊的构造函数,具有一般构造函数的所有特性,其形参是本类的对象的引用。其作用是使用一个已经存在的对象(由复制构造函数的参数指定),去初始化同类的一个新对象。如果程序员...
  • 复制构造函数总结

    千次阅读 2012-01-12 14:50:48
    1.同一类型的对象来初始化另一对象需要调用复制构造函数 例1:class A { public: A(){} A(const A& a){cout;} }; int main() { A a, c; A b = a;//显式复制构造函数(1) c = a;//赋值函数(2) return 0; ...
  •  我们已经会用构造函数初始化对象,那么我们能不能象简单变量的初始化一样,直接一个对象来初始化另一个对象呢?答案是肯定的。我们以前面定义的Point类为例:  Point pt1(15, 25);  Point pt2 = pt1; ...
  • C++ 复制构造函数

    千次阅读 2013-03-11 12:51:32
    复制构造函数: 只有单个形参,而且该形参是对本类类型对象的引用(常为const修饰,只读),这样的构造函数称为 复制构造函数。与默认的构造函数一样,复制构造函数可由编译器隐式调用。 复制构造函数用于: ...
  • C++——构造函数、析构函数以及复制构造函数

    千次阅读 多人点赞 2021-03-09 16:28:49
    1.2 为什么有构造函数?1.3 如何使用构造函数?1.4 构造函数的实现二、使用步骤 一、构造函数 在程序执行的过程中,当遇到与对声明语句时,程序会向操作系统申请一定的内存空间用于存放新建的对象。但是与普通变量...
  • 构造函数、复制构造函数和赋值操作符在生成对象和对象之间的复制时用到。如果类中没有显式定义这三种函数,那编译器通常会为我们定义(合成)。如果类中定义了一个带参数的构造函数,那么编译器就不会再自动合成默认...
  • 构造函数成员函数的一种,名字与类名相同,可以参数,不能返回值(void也不行)。 一个类可以多个构造函数。 如果定义类时没写构造函数,则编译器生成一个默认的无参构造函数,这个构造函数不做任何操作。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 249,039
精华内容 99,615
关键字:

复制构造函数有什么用