调用拷贝构造函数的情形 在C++中,下面三种对象需要调用拷贝构造函数(有时也称“复制构造函数”): 1) 一个对象作为函数参数,以值传递的方式传入函数体; 2) 一个对象作为函数返回值,以值传递的方式从函数返回 拷贝构造函数使程序更有效率,因为它不用再构造一个对象的时候改变构造函数的参数列表。设计拷贝构造函数是一个良好的风格,即使是编译系统会自动为你生成默认拷贝构造函数。 事实上,默认拷贝构造函数可以应付许多情况。 所以C++语法中除了提供缺省形式的构造函数外,还规范了另一种特殊的构造函数:拷贝构造函数,一种特殊的构造函数重载。 可见,拷贝构造函数是一种特殊的构造函数,函数的名称必须和类名称一致,它必须的一个参数是本类型的一个引用变量。 二. 拷贝构造函数的调用时机 在C++中,下面三种对象需要调用拷贝构造函数! 默认拷贝构造函数 很多时候在我们都不知道拷贝构造函数的情况下,传递对象给函数参数或者函数返回对象都能很好的进行,这是因为编译器会给我们自动产生一个拷贝构造函数,这就是“默认拷贝构造函数”,这个构造函数很简单
拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。拷贝构造函数通常用于: 通过使用另一个同类型的对象来初始化新创建的对象。 复制对象把它作为参数传递给函数。 复制对象,并从函数返回这个对象。 如果在类中没有定义拷贝构造函数,编译器会自行定义一个。如果类带有指针变量,并有动态内存分配,则它必须有一个拷贝构造函数。 拷贝构造函数的最常见形式如下: #include<iostream> using namespace std; class Line{ public: int getlength(); Line (int len);//简单的构造函数 Line(const Line&obj);//拷贝构造函数 ~Line();//析构函数 private: int *ptr; }; //成员函数的定义 line(10); display(line); system("pause"); return 0; } 运行结果为: 嗯,c中指针部分得复习,自己还没吃透,再吐槽一句,书上第一页说的没错,c+
假定有类T 则下列情况调用的函数是不一样的: T a = b; a=b; 第一种情况调用的是拷贝构造函数 第二种情况调用的是赋值运算符。 默认的拷贝构造函数执行的是浅拷贝,在对象涉及到动态分配的存储空间时,会出现问题。 在a中修改变量值后,b中的也发生改变。 出现内存泄漏(只new但是没有delete就会出现这样的问题) 一个地址被多次释放也会出错 要解决上面的问题,就要执行深拷贝 深拷贝使得每一个对象成员都有自己的内存空间。 要执行深拷贝,那么就要自己定义拷贝构造函数。 主要操作在于,对于动态分配的空间,重新new一块出来,再执行strcpy。 下面是一个拷贝构造函数的例子 String::String(const String && T){} 在上面这个例子之中,&&代表的是右值引用,扩大了临时变量的生命周期。
就类对象而言,相同类型的类对象是通过拷贝构造函数来完成整个复制过程的。下面举例说明拷贝构造函数的工作过程。 例如:类X的拷贝构造函数的形式为X(X& x)。 当用一个已初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用。 如果在类中没有显式地声明一个拷贝构造函数,那么,编译器将会自动生成一个默认的拷贝构造函数,该构造函数完成对象之间的位拷贝。位拷贝又称浅拷贝,后面将进行说明。 自定义拷贝构造函数是一种良好的编程风格,它可以阻止编译器形成默认的拷贝构造函数,提高源码效率。 当用一个已经初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用,如果你没有自定义拷贝构造函数的时候,系统将会提供给一个默认的拷贝构造函数来完成这个过程,上面代码的复制核心语句就是通过
拷贝构造函数 知识点: 解释:拷贝构造函数是一种特殊的构造函数,它具有一般构造函数的所有特性,但其形参是本类对象的引用。 拷贝构造函数的参数采用引用方式。 若把一个真实的类对象作为参数传到拷贝构造函数,引起无穷递归; 拷贝构造函数的名字必须与类名相同,且无返回值; 拷贝构造函数只有一个参数,必须为本类对象的引用; 每一个类必须有一个拷贝构造函数。 若用户定义类时未给出拷贝构造函数,则系统会自动产生一个缺省的拷贝构造函数; 该例重点阐述:为什么拷贝构造函数的参数必须为同类对象的引用? 调用两个参数的构造函数 调用拷贝构造函数 a=(3,4) c=(3,4) 调用拷贝构造函数 n=(5.6,7.9) 调用拷贝构造函数 调用两个参数的构造函数 (8.6,11.9) 本例中,当程序执行到
C++拷贝构造函数是一种特殊的构造函数,用于创建对象时,使用一个已有对象的内容来初始化新的对象。它接受一个同类对象作为参数,并按照该对象的数据成员的值来创建新的对象。 如果没有显式定义拷贝构造函数,编译器会提供一个默认的拷贝构造函数。默认的拷贝构造函数执行的是浅拷贝,即简单地将原对象的值复制给新对象的数据成员。 拷贝构造函数是通过对象名来调用的,而不是通过函数名来调用。 二、拷贝构造函数的特征 拷贝构造函数也是特殊的成员函数,其特征如下: 拷贝构造函数是构造函数的一个重载形式。 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。 d2,此处会调用Date类的拷贝构造函数 // 但Date类并没有显式定义拷贝构造函数,则编译器会给Date类生成一个默认的拷贝构造函数 Date d2(d1); return 0; } 注意:在编译器生成的默认拷贝构造函数中
拷贝构造函数 拷贝构造函数最常见的是当我们创建的对象是用该类的另一个对象来进行初始化的,此时调用的构造函数就是拷贝构造函数。拷贝构造函数实质上就是构造函数的重载。 当你不显式定义拷贝构造函数的时候,C++会给你提供一个默认拷贝构造函数,这和它提供默认构造函数是一样的。 但是当你一旦显式定义了构造函数和拷贝构造函数,那么C++将不再提供默认构造函数和默认拷贝构造函数。 下面这三种情形是常见的需要拷贝构造函数的场景。 注意:如果按照C.Show(C1)来接着分析,我们理所当然的会得出结论是这行代码将会调用3次拷贝构造函数,调用两次析构函数。实际上并非如此,C++的编译器设计者做了一定的优化措施。 这时候就需要我们自己动手实现一个拷贝构造函数。在构造函数中没有出现分配内存或者数组的情形下,我们使用默认拷贝构造函数就足够了。 深拷贝 深拷贝是需要在拷贝构造函数中进行内存分配或者是数组赋值操作。
今天就一个函数返回问题跟辉月兄弟讨论一番,大有所获,足以解决我们目前80%的问题,感觉对C++的掌握上升到了20%。 背景,现有字节数组ByteArray和字符串String,(不要激动,单片机嵌入式C++很难用起来标准类库) 我们需要实现函数String& ByteArray::ToHex() 其实这是我们在C#上非常常用的函数 经过一番探讨,我们发现关键点出在拷贝构造函数上面 测试环境:编译器Keil MDK 5.14,处理器STM32F407VG 1、进出两次拷贝 做了一个测试代码,两次调用拷贝构造函数 class A 2、进去拷贝出来引用 修改func函数,返回引用,少一次拷贝构造 B& fun(B c) { c.str = "c"; return c; } 执行结果如下: A a 0x2001FB70 0x2001FB88 => b 0x2001FB84 end ~B b 0x2001FB84 ~A b 0x2001FB84 ~B c 0x2001FB88 ~A c 0x2001FB88 更加彻底,没有任何拷贝构造函数被执行
&:防止无限循环拷贝 类名(类名 const& 参数名) { 函数体 } 三、拷贝构造函数的分类 浅拷贝:成员变量无动态内存(指针等)变量时,在拷贝构造函数内对成员变量只做简单的赋值,不做内存申请 深拷贝 Cperson person2=person1;//显示调用拷贝构造 } 四、默认拷贝构造函数(合成拷贝构造函数) 规则:如果没有主动给出拷贝构造,编译器会自动添加一个拷贝构造(做的是浅拷贝 但是,如果一个类有一个移动构造函数,则拷贝初始化有时会使用移动构造函数而非拷贝构造函数来完成。 九、绕过拷贝构造函数 在拷贝初始化过程中,编译器可以(但不是必须)跳过拷贝/移动构造函数,直接创建对象 但是,即使编译器库绕过了拷贝/移动构造函数,但在这个程序点上,拷贝/移动构造函数必须是存在且可访问的 //编译器略过了拷贝构造函数 十、拷贝赋值运算符(=) 可参考之前的构造函数篇或者运算符重载 拷贝构造函数与拷贝赋值运算符的关系 拷贝构造函数是用另一个对象来初始化一块内存区域,这块内存就是新对象的内存区
=0) strcpy(str,C.str); } 拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。 如果在类中没有定义拷贝构造函数,编译器会自行定义一个。如果类带有指针变量,并有动态内存分配,则它必须有一个拷贝构造函数。 Line( const Line &obj); // 拷贝构造函数 ~Line(); // 析构函数 private: int *ptr; }; // 成员函数定义,包括构造函数 Line::Line Line( const Line &obj); // 拷贝构造函数 ~Line(); // 析构函数 private: int *ptr; }; // 成员函数定义,包括构造函数 Line::Line 0; } 当上面的代码被编译和执行时,它会产生下列结果: 调用构造函数 调用拷贝构造函数并为指针 ptr 分配内存 调用拷贝构造函数并为指针 ptr 分配内存 line 大小 : 10 释放内存 调用拷贝构造函数并为指针
函数体为空 , 不做任何操作 ; 默认拷贝构造函数 : 如果 C++ 类中 没有定义拷贝构造函数 , C++ 编译器会自动为该类提供一个 " 默认的拷贝构造函数 " , 在函数中对成员变量进行简单的复制操作 在函数中对成员变量进行简单的复制操作 ; 没有定义拷贝构造函数 : 如果 没有为 C++ 类定义 拷贝构造函数 , C++ 编译器 将自动为该类 生成一个 默认的拷贝构造函数 ; 定义了拷贝构造函数 : 如果为 C++ 类 定义了 拷贝构造函数 , C++ 编译器 将不再自动生成默认的拷贝构造函数 ; 默认拷贝构造函数内容 : C++ 编译器 为类 定义的 默认拷贝构造函数 , 在函数内部将 现有对象 和 默认拷贝构造函数 : 如果 C++ 类中 没有定义 构造函数 时 , C++ 编译器 会提供 默认的 无参构造函数 和 默认的 拷贝构造函数 ; 提供 默认拷贝构造函数 : 如果 C++ 类中 , 复制 ; 特例 : 如果 C++ 类中 , 定义了 拷贝构造函数 , 那么 C++ 编译器不会提供 默认的无参构造函数 ; 2、代码示例 - 只定义拷贝构造函数 下面的代码中 , 定义了 拷贝构造函数
注意:析构 函数不能重载 对象生命周期结束时,C++编译系统系统自动调用析构函数 编译器生成的默认析构函数,对自定类型成员调用它的析构函数,对内置类型不做处理。 默认的拷贝构造函数对内置类型完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。而自定义类型是调用其拷贝构造函数完成拷贝的。 类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请 时,则拷贝构造函数是一定要写的,否则就是浅拷贝。 C++规定自定义的类型都会调用拷贝构造。 注意:拷贝构造时要传引用,不能传值。如果传值,根据C++规定,会调用拷贝构造,这样就会无穷递归下去,发生错误。 类中只有内置类型,没有显式写出拷贝构造函数,编译器会给出默认的拷贝构造函数,进行浅拷贝。
特征 拷贝构造函数也是特殊的成员函数,其特征如下: 拷贝构造函数是构造函数的一个重载形式。 d2,此处会调用Date类的拷贝构造函数 // 但Date类并没有显式定义拷贝构造函数,则编译器会给Date类生成一个默认的拷贝构造函数 Date d2(d1); return 0; } 这段代码演示了类的默认构造函数和拷贝构造函数的用法 在 C++ 中,当一个类的成员变量没有默认构造函数时,该类的默认构造函数就会被隐式地标记为已删除。这是因为编译器无法确定如何初始化这些成员变量。 如果把Time的构造函数删掉,那么Time的默认构造函数还原,那么编译器就会生成Time的拷贝构造函数来完成拷贝: 注意:在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定义类型是调用其拷贝构造函数完成拷贝的 在 C++ 中,浅拷贝和深拷贝是两种不同的对象复制方式,它们之间有以下区别: 浅拷贝(Shallow Copy): 浅拷贝是默认的复制行为,当使用赋值运算符(=)或者拷贝构造函数(T(const T
编译器自动生成的复制构造函数称为“默认复制构造函数”。 ,也就是会不会调用赋值构造函数的区别 如果函数F的参数是类A的对象,那么当F被调用时,类A的复制构造函数将被调用,换句话讲,形参的初始化也是靠实参调用拷贝构造函数进行的 #include<iostream 如果函数的返冋值是类 A 的对象,则函数返冋时,类 A 的复制构造函数被调用。换言之,作为函数返回值的对象是用复制构造函数初始化 的,而调用复制构造函数时的实参,就是 return 语句所返回的对象。 } }; A Func() { A a(4); return a; } int main() { cout << Func().v << endl; return 0; } //以上内容大部分转自[C+ +拷贝构造函数(复制构造函数)详解 (biancheng.net)](http://c.biancheng.net/view/151.html)
拷贝构造函数 上一期中我们讲述了构造函数的相关内容,谈到构造函数在形式上有几种分类,即带参数的、不带参数的以及参数列表初始化的,还有一种传引用的构造函数,称为拷贝构造函数,顾名思义,就是起到拷贝的功能, 我们还是用Point这个类作为例子进行讲解,拷贝构造函数就是参数类型为引用类型的构造函数。 class Point { double x,y; public: Point(Point & point); }; 浅拷贝 所有的类都有自己的拷贝构造函数,如果程序员自己没有写拷贝构造函数,那么系统会默认生成一个缺省的拷贝构造函数 ,它采取逐位复制的方法进行对象拷贝,又称为浅拷贝。 我们自己写一个Point类的浅拷贝的拷贝构造函数作为例子: Point::Point(Point & point) { x=point.x; y=point.y; } 这就是浅拷贝,即逐位复制。
构造函数可以有参数,可以发生重载。 5. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,,一旦用户显式定义编译器将不再生成。 6. (有些编译器可能会初始化为0,但是C++标准并没有规定) 解答:C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类型,如:int/char... 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不可以有参数的 不可以发生重载 4. 对象生命周期结束时,C++编译系统系统自动调用析构函数,而且只调用一次。 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。 4. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。
C++ 构造函数构造函数是 C++ 中一种特殊的成员函数,当创建类对象时自动调用。它用于初始化对象的状态,例如为属性分配初始值。构造函数与类同名,且没有返回值类型。 构造函数类型C++ 支持多种类型的构造函数,用于满足不同的初始化需求:默认构造函数: 不带参数的构造函数,通常用于初始化对象的默认状态。带参数构造函数: 允许传入参数来初始化对象的状态。 拷贝构造函数: 用于从另一个已存在的对象创建新对象。移动构造函数: 用于从即将销毁的临时对象转移资源到新对象。默认构造函数默认构造函数是最简单的构造函数,不接受任何参数。 << car1.brand << " " << car1.model << " " << car1.year << endl; // 输出:Ford Mustang 1967 return 0;}拷贝构造函数拷贝构造函数用于从另一个已存在的对象创建新对象 总结构造函数是 C++ 中重要的面向对象编程机制,用于初始化和管理对象的状态。通过理解不同类型的构造函数及其用法,您可以创建健壮且可维护的 C++ 代码。
,C++编译器会自动生成一个无参的默认构造函数,一旦用户显示定义,编译器将不在生成。 注意:析构函数不能重载 对象生命周期结束时,C++编译系统系统自动调用析构函数。 原因:传值拷贝时 第一步:开辟一个临时空间; 第二步:由于临时空间是需要构造的,重新调用拷贝构造函数(无穷递归形成…) 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。 浅拷贝不能实现复杂的类拷贝,涉及指针等内容会拷贝失败。 拷贝构造函数典型调用场景: 使用已存在对象创建新对象 函数参数类型为类类型对象 函数返回值类型为类类型对象 4 赋值运算符重载 运算符重载 C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数
拷贝构造函数 拷贝构造函数的也是一种构造函数,它的作用是将一个类的成员拷贝到另一个类中,类似于赋值。拷贝构造函数分为深拷贝和浅拷贝。 先来定义一个拷贝构造函数(构造函数可以重载),看招: #include<iostream> using namespace std; class date { public: date(int year int month=0, int day=0) { _year = year; _month = month; _day = day; } date(const date& d)//拷贝构造函数 拷贝构造函数的使用方法 拷贝构造函数的使用: 1.使用();2.使用'=';像这样 拷贝构造函数与赋值运算符的区别 那么拷贝构造函数和赋值运算符有什么区别呢,先来看一段代码对比一下: int main ) { date d1(20244, 4, 24); date d2=d1; date d3; d3= d1;//编译器会自动将其转化为d3(d1); return 0; } 这里d2采用的拷贝构造函数的方式
对于一个局部域中的多个对象在进行销毁时,c++规定后创建的对象先析构。 那么我们什么时候该显示写析构函数呢? 三、拷贝构造函数 拷贝构造函数是构造函数的一个重载,它用于完成对象的拷贝。 它的特点如下: 1. c++规定对象只要发生拷贝行为,就必须调用拷贝构造,包括对象传参或者做返回值,都需要产生一份临时拷贝。 2. 拷贝构造函数的第一个参数必须是类类型的引用,而不是对象的值。 因为对象在传值传参的时候需要调用拷贝构造,如果拷贝构造的参数带有对象的临时拷贝,那就会再次调用拷贝构造,以至于发生无限递归。 3. 如果我们没有显示定义拷贝构造函数,编译器会自动生成一个拷贝构造。 这个自动生成的拷贝构造在完成拷贝工作时,对内置类型会完成它的浅拷贝,对类类型则会调用该类的拷贝构造函数。