写点什么

c++ 构造函数详解

用户头像
若尘
关注
发布于: 2 小时前
c++ 构造函数详解

c++ 构造函数详解

构造函数是干什么的

  • 该类对象被创建的时候,编译系统对象分配内存空间,并自动调用该构造函数,由构造函数完成成员的初始化工作,故:构造函数的作用:初始化对象的数据成员

构造函数的分类

  • 无参构造函数

  • 带默认值的构造函数

  • 有参(无默认值)的构造函数

  • 复制构造函数(拷贝构造函数)

  • 一种特殊的构造函数,当对象之间复制时会自动调用拷贝构造函数

  • 若类中没有显示定义拷贝构造函数,则系统会自动生成默认拷贝构造函数


  #include <iostream>  using namespace std;    class Coordinate  {  public:    // 无参构造函数    // 如果创建一个类你没有写任何构造函数,则系统自动生成默认的构造函数,函数为空,什么都不干    // 如果自己显示定义了一个构造函数,则不会调用系统的构造函数    Coordinate()    {      c_x = 0;      c_y = 0;    }           // 一般构造函数    Coordinate(double x, double y):c_x(x), c_y(y){}   //列表初始化    // 一般构造函数可以有多个,创建对象时根据传入的参数不同调用不同的构造函数      Coordinate(const Coordinate& c)    {      // 复制对象c中的数据成员      c_x = c.c_x;      c_y = c.c_y;    }      // 等号运算符重载    Coordinate& operator= (const Coordinate& rhs)    {      // 首先检测等号右边的是否就是等号左边的对象本身,如果是,直接返回即可      if(this == &rhs)        return* this;      // 复制等号右边的成员到左边的对象中      this->c_x = rhs.c_x;      this->c_y = rhs.c_y;      return* this;    }      double get_x()    {      return c_x;    }      double get_y()    {      return c_y;    }    private:    double c_x;    double c_y;  };    int main()  {    // 调用无参构造函数,c1 = 0,c2 = 0    Coordinate c1, c2;    // 调用一般构造函数,调用显示定义构造函数    Coordinate c3(1.0, 2.0);    c1 = c3;    //将c3的值赋值给c1,调用"="重载    Coordinate c5(c2);    Coordinate c4 = c2;    // 调用浅拷贝函数,参数为c2    cout<<"c1 = "<<"("<<c1.get_x()<<", "<<c1.get_y()<<")"<<endl      <<"c2 = "<<"("<<c2.get_x()<<", "<<c2.get_y()<<")"<<endl      <<"c3 = "<<"("<<c3.get_x()<<", "<<c3.get_y()<<")"<<endl      <<"c4 = "<<"("<<c4.get_x()<<", "<<c4.get_y()<<")"<<endl      <<"c5 = "<<"("<<c5.get_x()<<", "<<c5.get_y()<<")"<<endl;    return 0;  }
复制代码


  c1 = (1, 2)  c2 = (0, 0)  c3 = (1, 2)  c4 = (0, 0)  c5 = (0, 0)  请按任意键继续. . .
复制代码

拷贝构造函数

  • 拷贝构造函数是一种特殊的构造函数,具有单个形参,该形参(常用 const 修饰)是对该类型的引用。当定义一个新对象并用同一类型的对象都它进行初始化时,将显示使用拷贝构造函数,当该类型的对象传递给函数返回该类型的对象时,将隐式调用拷贝构造函数

  • 当类中有一个数据成员是指针时,或者有成员表示在构造函数中分配的其他资源,必须显示定义拷贝构造函数

  • 构造函数的使用情况

  • 一个对象以值传递的方式传入函数体

  • 一个对象以值传递的方式从函数体返回

  • 一个对象需要通过另一个对象进行初始化


  #include <iostream>  using namespace std;    class Test  {  public:    // 构造函数    Test(int a):t_a(a){    cout<<"creat: "<<t_a<<endl;    }      // 拷贝构造函数    Test(const Test& T)    {      t_a = T.t_a;      cout<<"copy"<<endl;    }      // 析构函数    ~Test()    {      cout<<"delete: "<<t_a<<endl;    }      // 显示函数    void show()    {      cout<<t_a<<endl;     }    private:    int t_a;  };    // 全局函数,传入的是对象  void fun(Test C)  {    cout<<"test"<<endl;  }    int main()  {    Test t(1);    // 函数中传入对象    fun(t);    return 0;  }
复制代码


  creat: 1  copy  test  delete: 1  delete: 1  请按任意键继续. . .
复制代码

浅拷贝与深拷贝

  • 浅拷贝

  • 所谓浅拷贝,指的是在对象复制时,只对对象中的数据成员进行简单的赋值,默认拷贝构造函数执行的也是浅拷贝。也就是增加了一个指针,指向原来已经存在的内存。 正常情况下,“浅拷贝”已经能很好的工作,但是一旦对象存在动态成员,浅拷贝就会出问题。让我们考虑下面一段代码:


  #include <iostream>  #include <assert.h>      using namespace std;    class Test  {  public:    Test(){      p = new int(10);    }      ~Test(){      assert(p != NULL);     // assert()作用是如果他的条件返回错误,则终止程序执行       delete p;    }  private:    int x;    int y;    int* p;  };    int main()  {    Test t1;    Test t2(t1);    // 调用默认拷贝构造函数    return 0;  }
复制代码


上述程序崩溃。在使用 t1 复制 t2 时,进行的是浅拷贝,只是将成员的值进行赋值。此时,t1.p = t2.p, 即两个指针指向了堆里的同一个空间。这样,析构函数会被调用两次,这就是错误出现的原因。此问题的解决方法是“深拷贝”。


  • 深拷贝

  • 深拷贝就是对于对象中的动态成员,并不只是简单的赋值,而是重新分配空间,即资源重新分配。上述代码处理如下:


  #include <iostream>  #include <assert.h>      using namespace std;    class Test  {  public:    Test(){      x = 0;      y = 0;      p = new int(10);    }      Test(const Test& t)    {      x = t.x;      y = t.y;      p = new int(10);      *p = *(t.p);    }      ~Test(){      assert(p != NULL);     // assert()作用是如果他的条件返回错误,则终止程序执行       delete p;    }      int get_x(){return x;}    int get_y(){return y;}  private:    int x;    int y;    int* p;  };    int main()  {    Test t1;    Test t2(t1);    // 调用默认拷贝构造函数    cout<<"("<<t1.get_x()<<", "<<t1.get_y()<<")"<<endl      <<"("<<t2.get_x()<<", "<<t2.get_y()<<")"<<endl;    return 0;  }
复制代码


(0, 0)(0, 0)请按任意键继续. . .
复制代码


此时 t1 与 t2 的 p 各自指向一段内存空间,但他们指向的内容相同,这就是“深拷贝”。

发布于: 2 小时前阅读数: 3
用户头像

若尘

关注

还未添加个人签名 2021.01.11 加入

还未添加个人简介

评论

发布
暂无评论
c++ 构造函数详解