C++拷贝构造函数(复制构造函数)
有的、已经存在的数据创建出一份新的数据,最终的结果是多了一份相同的数据。例如,将Word 文档拷贝到U盘去复印店打印,将D 盘的图片拷贝到桌面以方便浏览,将重要的文件上传到百度网盘以防止丢失等,都是「创建一份新数据」的意思。
在C++ 中,拷贝并没有脱离它本来的含义,只是将这个含义进行了“特化”,是指用已经存在的对象创建出一个新的对象。从本质上讲,对象也是一份数据,因为它会占用内存。
严格来说,对象的创建包括两个阶段,首先要分配内存空间,然后再进行初始化:
?分配内存很好理解,就是在堆区、栈区或者全局数据区留出足够多的字节。这个时候的内存还比较“原始”,没有被“教化”,它所包含的数据一般是零值或者随机值,没有实际的意义。
?初始化就是首次对内存赋值,让它的数据有意义。注意是首次赋值,再次赋值不叫初始化。初始化的时候还可以为对象分配其他的资源(打开文件、连接网络、动态分配内存等),或者提前进行一些计算(根据价格和数量计算出总价、根据长度和宽度计算出矩形的面积等)等。说白了,初始化就是调用构造函数。
很明显,这里所说的拷贝是在初始化阶段进行的,也就是用其它对象的数据来初始化新对象的内存。
那么,如何用拷贝的方式来初始化一个对象呢?其实这样的例子比比皆是,string 类就是一个典型的例子。
1.#include
2.#include
https://www.360docs.net/doc/0d1527851.html,ing namespace std;
4.
5.void func(string str){
6.cout< 7.} 8. 9.int main(){ 10.string s1 ="https://www.360docs.net/doc/0d1527851.html,"; 11.string s2(s1); 12.string s3 = s1; 13.string s4 = s1 +" "+ s2; 14.func(s1); 15.cout< 16. 17.return0; 18.} 运行结果: https://www.360docs.net/doc/0d1527851.html, https://www.360docs.net/doc/0d1527851.html, https://www.360docs.net/doc/0d1527851.html, https://www.360docs.net/doc/0d1527851.html, https://www.360docs.net/doc/0d1527851.html, https://www.360docs.net/doc/0d1527851.html, s1、s2、s3、s4 以及func() 的形参str,都是使用拷贝的方式来初始化的。 对于s1,表面上看起来是将一个字符串直接赋值给了s1,实际上在内部 进行了类型转换,将const char * 类型转换为string 类型后才赋值的, 这点我们将在《C++转换构造函数》一节中详细讲解。s4 也是类似的道 理。 对于s1、s2、s3、s4,都是将其它对象的数据拷贝给当前对象,以完成当前对象的初始化。 对于func() 的形参str,其实在定义时就为它分配了内存,但是此时并没有初始化,只有等到调用func() 时,才会将其它对象的数据拷贝给str 以完成初始化。 当以拷贝的方式初始化一个对象时,会调用一个特殊的构造函数,就是拷贝构造函数(Copy Constructor)。 下面的例子演示了拷贝构造函数的定义和使用: 1.#include 2.#include https://www.360docs.net/doc/0d1527851.html,ing namespace std; 4. 5.class Student{ 6.public: 7.Student(string name ="",int age =0,float score =0.0f);//普通构造函数 8.Student(const Student &stu);//拷贝构造函数(声明) 9.public: 10.void display(); 11.private: 12.string m_name; 13.int m_age; 14.float m_score; 15.}; 16. 17.Student::Student(string name,int age,float score):m_name(name),m_age(age), m_score(score){} 18. 19.//拷贝构造函数(定义) 20.Student::Student(const Student &stu){ 21.this->m_name = stu.m_name; 22.this->m_age = stu.m_age; 23.this->m_score = stu.m_score; 24. 25.cout<<"Copy constructor was called."< 26.} 27. 28.void Student::display(){ 29.cout< 30.} 31. 32.int main(){ 33.Student stu1("小明",16,90.5); 34.Student stu2 = stu1;//调用拷贝构造函数 35.Student stu3(stu1);//调用拷贝构造函数 36.stu1.display(); 37.stu2.display(); 38.stu3.display(); 39. 40.return0; 41.} 运行结果: Copy constructor was called. Copy constructor was called. 小明的年龄是16,成绩是90.5 小明的年龄是16,成绩是90.5 小明的年龄是16,成绩是90.5 第8 行是拷贝构造函数的声明,第20 行是拷贝构造函数的定义。拷贝构造函数只有一个参数,它的类型是当前类的引用,而且一般都是const 引用。 1) 为什么必须是当前类的引用呢? 如果拷贝构造函数的参数不是当前类的引用,而是当前类的对象,那么在调用拷贝构造函数时,会将另外一个对象直接传递给形参,这本身就是一次拷贝,会再次调用拷贝构造函数,然后又将一个对象直接传递给了形参,将继续调用拷贝构造函数……这个过程会一直持续下去,没有尽头,陷入死循环。 只有当参数是当前类的引用时,才不会导致再次调用拷贝构造函数,这不仅是逻辑上的要求,也是C++ 语法的要求。 2) 为什么是const 引用呢? 拷贝构造函数的目的是用其它对象的数据来初始化当前对象,并没有期望更改其它对象的数据,添加const 限制后,这个含义更加明确了。 另外一个原因是,添加const 限制后,可以将const 对象和非const 对象传递给形参了,因为非const 类型可以转换为const 类型。如果没有const 限制,就不能将const 对象传递给形参,因为const 类型不能转换为非const 类型,这就意味着,不能使用const 对象来初始化当前对象了。 以上面的Student 类为例,将const 去掉后,拷贝构造函数的原型变为: 此时,下面的代码就会发生错误: 1.const Student stu1("小明",16,90.5); 2.Student stu2 = stu1; 3.Student stu3(stu1); 当然,你也可以再添加一个参数为const 引用的拷贝构造函数,这样就不会出错了。换句话说,一个类可以同时存在两个拷贝构造函数,一个函数的参数为const 引用,另一个函数的参数为非const 引用。 默认拷贝构造函数 在前面的教程中,我们还没有讲解拷贝构造函数,但是却已经在使用拷贝的方式创建对象了,并且也没有引发什么错误。这是因为,如果程序员没有显式地定义拷贝构造函数,那么编译器会自动生成一个默认的拷贝构造函数。这个默认的拷贝构造函数很简单,就是使用“老对象”的成员变量对“新对象”的成员变量进行一一赋值,和上面Student 类的拷贝构造函数非常类似。 对于简单的类,默认拷贝构造函数一般是够用的,我们也没有必要再显式地定义一个功能类似的拷贝构造函数。但是当类持有其它资源时,如动态分配的内存、打开的文件、指向其他数据的指针、网络连接等,默认拷贝构造函数就不能拷贝这些资源,我们必须显式地定义拷贝构造函数,以完整地拷贝对象的所有数据,这点我们将在《C++深拷贝和浅拷贝》一节中深入讲解。 C#默认构造函数的作用 本文详细介绍C#默认构造函数的作用 构造函数主要用来初始化对象。它又分为静态(static)和实例(instance)构造函数两种类别。大家应该都了解如果来写类的构造函数,这里只说下默认构造函数的作用,以及在类中保留默认构造函数的重要性。实际上,我说错了。正确的说法是:以及在类中保留空参数构造函数的重要性。我们来写一个类A,代码如下: view plaincopy to clipboardprint? public class A { public int Number; //数字 public string Word; //文本 } //在Test类中实例化 public class Test { static void Main() { A a = new A(); //实例化,A()即为类A的默认构造函数 Console.WriteLine(“Number = {0}"nWord = {1}”,a.Number,a.Word); Console.read(); } } 输出的结果是: Number = 0 Word = ******************************* using System; class Point { public int x, y,z; public Point() { x = 0; y = 0; z = 0; } public Point(int x, int y,int z) { //把函数内容补充完整 this.x = x; this.y =y; this.z =z; } public override string ToString() { return(String.Format("({0},{1},{2})", x, y,z)); } } class MainClass { static void Main() { Point p1 = new Point(); Point p2 = new Point(10,20,30); Console.WriteLine("三维中各点坐标:"); Console.WriteLine("点1的坐标为{0}", p1); Console.WriteLine("点2的坐标为{0}", p2); } } ******************************************************************************* ********* C#类的继承,构造函数实现及其调用顺序 类层层派生,在实例化的时候构造函数的调用顺序是怎样的? --从顶层基类开始向子类方向顺序调用无参构造. 默认构造(无参构造)和带参构造什么时候调用?--默认将从顶层父类的默认构造一直调用到当前类的默认构造. 下面是示例: /**//*--===------------------------------------------===--- 作者:许明会 日期:类的派生和构造函数间的关系,调用层次及实现 日期:2008年1月18日 17:30:43 若希望类能够有派生类,必须为其实现默认构造函数. 若类没有实现带参构造,编译器将自动创建默认构造函数. 若类实现了带参构造,则编译器不会自动生成默认构造. --===------------------------------------------===---*/ using System; namespace xumh { public class MyClass { public MyClass () { 有的、已经存在的数据创建出一份新的数据,最终的结果是多了一份相同的数据。例如,将Word 文档拷贝到U盘去复印店打印,将D 盘的图片拷贝到桌面以方便浏览,将重要的文件上传到百度网盘以防止丢失等,都是「创建一份新数据」的意思。 在C++ 中,拷贝并没有脱离它本来的含义,只是将这个含义进行了“特化”,是指用已经存在的对象创建出一个新的对象。从本质上讲,对象也是一份数据,因为它会占用内存。 严格来说,对象的创建包括两个阶段,首先要分配内存空间,然后再进行初始化: ?分配内存很好理解,就是在堆区、栈区或者全局数据区留出足够多的字节。这个时候的内存还比较“原始”,没有被“教化”,它所包含的数据一般是零值或者随机值,没有实际的意义。 ?初始化就是首次对内存赋值,让它的数据有意义。注意是首次赋值,再次赋值不叫初始化。初始化的时候还可以为对象分配其他的资源(打开文件、连接网络、动态分配内存等),或者提前进行一些计算(根据价格和数量计算出总价、根据长度和宽度计算出矩形的面积等)等。说白了,初始化就是调用构造函数。 很明显,这里所说的拷贝是在初始化阶段进行的,也就是用其它对象的数据来初始化新对象的内存。 那么,如何用拷贝的方式来初始化一个对象呢?其实这样的例子比比皆是,string 类就是一个典型的例子。 1.#include 定义类的构造函数 作者:lyb661 时间:20150613 定义类的构造函数有如下几种方法: 1、使用默认构造函数(类不另行定义构造函数):能够创建一个类对象,但不能初始化类的各个成员。 2、显式定义带有参数的构造函数:在类方法中定义,使用多个参数初始化类的各个数据成员。 3、定义有默认值的构造函数:构造函数原型中为类的各个成员提供默认值。 4、使用构造函数初始化列表:这个构造函数初始化成员的方式显得更紧凑。 例如:有一个学生类。其中存储了学生的姓名、学号和分数。 class Student { private: std::string name; long number; double scores; public: Student(){}//1:default constructor Student(const std::string& na,long nu,double sc); Student(const std:;string& na="",long nu=0,double sc=0.0); Student(const std:;string& na="none",long nu=0,double sc=0.0):name(na),number(nu),scores(sc){} ……….. void display() const; //void set(std::string na,long nu,double sc); }; ......... Student::Student(const std::string& na,long nu,double sc) { name=na; number=nu; scores=sc; } void Student::display()const { std::cout<<"Name: "< 拷贝构造函数 一. 什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: int a = 100; int b = a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。下面看一个类对象拷贝的简单例子。 #include C默认构造函数的作用
C++拷贝构造函数(复制构造函数)
定义构造函数的四种方法
(完整版)拷贝构造函数