解释网站为什么这样做,wordpress 代码压缩,跨境电商网站建设主管岗位职责,海淀地区网站建设目录
一、 概念
二、特征 正确的拷贝构造函数写法#xff1a;
拷贝函数的另一种写法
三、若未显式定义#xff0c;编译器会生成默认的拷贝构造函数。
四、编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了#xff0c;还需要自己显式实现吗#xff1f;
深拷…目录
一、 概念
二、特征 正确的拷贝构造函数写法
拷贝函数的另一种写法
三、若未显式定义编译器会生成默认的拷贝构造函数。
四、编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了还需要自己显式实现吗
深拷贝的写法
五、拷贝构造函数典型调用场景
六、总结 一、 概念
在现实生活中可能存在一个与你一样的自己我们称其为双胞胎。
那在创建对象时可否创建一个与已存在对象一某一样的新对象呢拷贝构造函数只有单个形参该形参是对本类类型对象的引用(一般常用const修饰)在用已存在的类类型对象创建新对象时由编译器自动调用。 二、特征
拷贝构造函数也是特殊的成员函数其特征如下
拷贝构造函数是构造函数的一个重载形式。拷贝构造函数的参数只有一个且必须是类类型对象的引用使用传值方式编译器直接报错因为会引发无穷递归调用。若未显式定义编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝这种拷贝叫做浅拷贝或者值拷贝。编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了还需要自己显式实现吗当然像日期类这样的类是没必要的。那么下面的类呢验证一下试试拷贝构造函数典型调用场景
使用已存在对象创建新对象函数参数类型为类类型对象函数返回值类型为类类型对象
class Date
{
public:Date(int year 1900, int month 1, int day 1){_year year;_month month;_day day;}Date(const Date d) // 正确写法{// this-_year d._year;_year d._year;_month d._month;_day d._day;}Date(Date d)// 错误写法 它不能用于从常量对象或临时对象进行拷贝构造{_year d._year;_month d._month;_day d._day;}Date(Date d)// 错误写法编译报错会引发无穷递归{_year d._year;_month d._month;_day d._day;}private:int _year;int _month;int _day;
};
int main()
{Date d1;// 拷贝构造用同类型的对象拷贝初始化Date d2(d1);return 0;
}正确的拷贝构造函数写法
Date(const Date d) // 正确写法
{// this-_year d._year;_year d._year;_month d._month;_day d._day;
}
这是正确的拷贝构造函数写法。它接受一个对Date类型的常量引用作为参数这意味着它可以用于从常量对象、非常量对象甚至是临时对象进行拷贝构造。由于它的灵活性这是最常用的拷贝构造函数定义方式。 Date(Date d){_year d._year;_month d._month;_day d._day;}
不能接收常量对象这个构造函数只接受非常量引用Date这意味着你不能使用它来拷贝一个常量对象。如果试图这样做编译器会报错因为常量对象不能被非常量引用所绑定。不能接收临时对象在C中临时对象也称为右值经常出现在表达式中例如函数返回值或者类型转换的结果。由于这个拷贝构造函数不接受右值引用或常量引用因此它不能用于拷贝这些临时对象。发生错误操作时没有报错赋值反了 Date(Date d)// 错误写法编译报错会引发无穷递归{_year d._year;_month d._month;_day d._day;}
这个构造函数是错误的会引发无穷递归。原因在于当试图用这个构造函数创建一个Date对象时它会尝试以值传递的方式接收一个Date对象作为参数。为了构造这个参数对象d又需要调用拷贝构造函数这会导致无限递归调用最终耗尽栈空间并导致程序崩溃。 class Date
{
public:Date(int year, int month, int day){_year year;_month month;_day day;}/*Date(Date d){d._year _year;d._month _month;d._day _day;}*/// Date d3(d2);//Date(const Date d)//{// // this-_year d._year;// _year d._year;// _month d._month;// _day d._day;//}Date(Date* d){_year d-_year;_month d-_month;_day d-_day;}void Print(){cout _year - _month - _day endl;}
private:// 给缺省值int _year 1;int _month 1;int _day 1;
};typedef int DataType;
class Stack
{
public:Stack(size_t capacity 3){cout Stack(size_t capacity 3) endl;_array (DataType*)malloc(sizeof(DataType) * capacity);if (NULL _array){perror(malloc申请空间失败!!!);return;}_capacity capacity;_size 0;}// Stack st2 st1;Stack(const Stack st){_array (DataType*)malloc(sizeof(DataType) * st._capacity);if (NULL _array){perror(malloc申请空间失败!!!);return;}memcpy(_array, st._array, sizeof(DataType) * st._size);_size st._size;_capacity st._capacity;}void Push(DataType data){// CheckCapacity();_array[_size] data;_size;}bool Empty(){return _size 0;}DataType Top(){return _array[_size - 1];}void Pop(){--_size;}// 其他方法...~Stack(){cout ~Stack() endl;if (_array){free(_array);_array NULL;_capacity 0;_size 0;}}
private:DataType* _array;int _capacity;int _size;
};
拷贝函数的另一种写法
int main()
{Date d2(2024, 4, 9);// 下面这两种写法是等价的Date d3(d2);Date d4 d2; // 这也是拷贝构造d2.Print();d3.Print();//func(d2);/*Date d3(d2);d3.Print();*/return 0;
} 三、若未显式定义编译器会生成默认的拷贝构造函数。
默认的拷贝构造函数对象按内存存储按字节序完成拷贝这种拷贝叫做浅拷贝或者值拷贝。
class Time
{
public:Time(){_hour 1;_minute 1;_second 1;}Time(const Time t){_hour t._hour;_minute t._minute;_second t._second;cout Time::Time(const Time) endl;}
private:int _hour;int _minute;int _second;
};
class Date
{
private:// 基本类型(内置类型)int _year 1970;int _month 1;int _day 1;// 自定义类型Time _t;
};
int main()
{Date d1;// 用已经存在的d1拷贝构造d2此处会调用Date类的拷贝构造函数// 但Date类并没有显式定义拷贝构造函数则编译器会给Date类生成一个默认的拷贝构造函数Date d2(d1);return 0;
}在上述代码中Date 类并没有显式定义拷贝构造函数。当代码中尝试通过已有的 Date 对象 d1 来拷贝构造一个新的 Date 对象 d2 时由于没有找到用户定义的拷贝构造函数编译器会自动为 Date 类生成一个默认的拷贝构造函数。
这个默认生成的拷贝构造函数会完成以下任务
对于基本数据类型成员直接拷贝其值。在 Date 类中_year、_month 和 _day 这三个整型成员变量会直接被赋值即新对象 d2 的这些成员会获得与 d1 相同的值。对于自定义类型成员调用该类型的拷贝构造函数。在 Date 类中_t 是 Time 类型的成员变量。当默认拷贝构造函数被调用时它会进一步调用 Time 类的拷贝构造函数来初始化新对象 d2 中的 _t 成员。这就是为什么在上述代码中即使没有显式编写拷贝操作仍然可以看到 Time 类的拷贝构造函数被调用的输出。
注意在编译器生成的默认拷贝构造函数中内置类型是按照字节方式直接拷贝的而自定义类型是调用其拷贝构造函数完成拷贝的。
四、编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了还需要自己显式实现吗
尽管编译器生成的默认拷贝构造函数可以完成字节序的值拷贝但在某些情况下仍然需要自己显式实现拷贝构造函数。这主要是因为默认拷贝构造函数执行的是浅拷贝它会拷贝对象的所有成员变量但如果对象中包含指针或动态分配的资源如使用 new 或 malloc 分配的内存浅拷贝可能会导致问题。
当然像日期类这样的类是没必要的。那么下面的类呢验证一下试试
// 这里会发现下面的程序会崩溃掉这里就需要我们以后讲的深拷贝去解决。
typedef int DataType;
class Stack
{
public:Stack(size_t capacity 10){_array (DataType*)malloc(capacity * sizeof(DataType));if (nullptr _array){perror(malloc申请空间失败);return;}_size 0;_capacity capacity;}void Push(const DataType data){// CheckCapacity();_array[_size] data;_size;}~Stack(){if (_array){free(_array);_array nullptr;_capacity 0;_size 0;}}
private:DataType* _array;size_t _size;size_t _capacity;
};
int main()
{Stack s1;s1.Push(1);s1.Push(2);s1.Push(3);s1.Push(4);Stack s2(s1);return 0;
}Stack s2(s1);
这里试图用s1来初始化s2。由于没有为Stack类提供自定义的拷贝构造函数编译器会使用默认的拷贝构造函数。这个默认的拷贝构造函数将s1的_array指针值直接拷贝给s2的_array这意味着s1和s2的_array成员现在指向同一块内存地址。当s1和s2的生命周期结束时它们的析构函数都会被调用并试图释放同一块内存这会导致未定义行为通常是程序崩溃因为同一块内存被释放了两次double free。 注意类中如果没有涉及资源申请时拷贝构造函数是否写都可以一旦涉及到资源申请时则拷贝构造函数是一定要写的否则就是浅拷贝。 深拷贝的写法
class Date
{
public:Date(int year, int month, int day){_year year;_month month;_day day;}/*Date(Date d){d._year _year;d._month _month;d._day _day;}*/// Date d3(d2);//Date(const Date d)//{// // this-_year d._year;// _year d._year;// _month d._month;// _day d._day;//}Date(Date* d){_year d-_year;_month d-_month;_day d-_day;}void Print(){cout _year - _month - _day endl;}
private:// 给缺省值int _year 1;int _month 1;int _day 1;
};typedef int DataType;
class Stack
{
public:Stack(size_t capacity 3){cout Stack(size_t capacity 3) endl;_array (DataType*)malloc(sizeof(DataType) * capacity);if (NULL _array){perror(malloc申请空间失败!!!);return;}_capacity capacity;_size 0; }// Stack st2 st1;Stack(const Stack st){_array (DataType*)malloc(sizeof(DataType) * st._capacity);if (NULL _array){perror(malloc申请空间失败!!!);return;}memcpy(_array, st._array, sizeof(DataType) * st._size);_size st._size;_capacity st._capacity;}void Push(DataType data){// CheckCapacity();_array[_size] data;_size;}bool Empty(){return _size 0;}DataType Top(){return _array[_size - 1];}void Pop(){--_size;}// 其他方法...~Stack(){cout ~Stack() endl;if (_array){free(_array);_array NULL;_capacity 0;_size 0;}}
private:DataType* _array;int _capacity;int _size;
};void func(Date d)
{d.Print();
}class MyQueue
{
private:Stack _st1;Stack _st2;int _size 0;
};int main()
{Date d2(2024, 4, 9);Date d4 d2; d4.Print();Stack st1(10);st1.Push(1);st1.Push(1);st1.Push(1);Stack st2 st1;st2.Push(2);st2.Push(2);while (!st2.Empty()){cout st2.Top() ;st2.Pop();}cout endl;while (!st1.Empty()){cout st1.Top() ;st1.Pop();}cout endl;MyQueue q1;MyQueue q2(q1);return 0;
}
拷贝构造函数创建的对象为新对象分配足够的内存空间来存储栈中的元素。内存的大小是根据原始对象的容量_capacity来计算的。使用memcpy函数将原始对象栈中的元素复制到新分配的内存中。将新对象的_size和_capacity设置为与原始对象相同的值。 MyQueue类中的成员变量每个MyQueue对象都包含两个Stack对象因此当q1和q2销毁时它们的四个Stack成员变量q1._st1, q1._st2, q2._st1, q2._st2也会被销毁每个Stack成员的析构函数都会被调用。这里增加了4次析构函数的调用。有一点需要注意如果MyQueue类没有定义拷贝构造函数并且默认使用了浅拷贝即只拷贝成员变量的值而不是它们所指向的内容那么q2中的_st1和_st2实际上只是q1中对应成员的简单复制指针或引用的复制。在这种情况下析构函数的调用次数可能会少于6次因为多个对象可能共享相同的资源。但在上述代码中我们假设MyQueue的拷贝构造函数进行了深拷贝即创建了Stack对象的独立副本因此每个Stack对象都有自己的生命周期并在结束时调用析构函数。 五、拷贝构造函数典型调用场景
使用已存在对象创建新对象函数参数类型为类类型对象函数返回值类型为类类型对象
class Date
{
public:Date(int year, int month, int day){cout Date(int,int,int): this endl;}Date(const Date d){cout Date(const Date d): this endl;}~Date(){cout ~Date(): this endl;}
private:int _year;int _month;int _day;
};
Date Test(Date d)
{Date temp(d);return temp;
}
int main()
{Date d1(2022, 1, 13);Test(d1);return 0;
} 构造函数 Date(int year, int month, int day) Date(int year, int month, int day){cout Date(int,int,int): this endl;}拷贝构造函数 Date(const Date d)
当创建一个已存在Date对象的副本时会调用它。同样当这个构造函数被调用时会打印一条消息和当前对象的地址。
Date() ~Date(){cout ~Date(): this endl;}
为了提高程序效率一般对象传参时尽量使用引用类型返回时根据实际场景能用引用尽量使用引用。
六、总结 今天就先到这了 看到这里了还不给博主扣个 ⛳️ 点赞☀️收藏 ⭐️ 关注
你们的点赞就是博主更新最大的动力 有问题可以评论或者私信呢秒回哦。 文章转载自: http://www.morning.c7624.cn.gov.cn.c7624.cn http://www.morning.uycvv.cn.gov.cn.uycvv.cn http://www.morning.kpfds.cn.gov.cn.kpfds.cn http://www.morning.ndfwh.cn.gov.cn.ndfwh.cn http://www.morning.yhyqg.cn.gov.cn.yhyqg.cn http://www.morning.tnwgc.cn.gov.cn.tnwgc.cn http://www.morning.jpzcq.cn.gov.cn.jpzcq.cn http://www.morning.cwrnr.cn.gov.cn.cwrnr.cn http://www.morning.sbczr.cn.gov.cn.sbczr.cn http://www.morning.xjkfb.cn.gov.cn.xjkfb.cn http://www.morning.lbqt.cn.gov.cn.lbqt.cn http://www.morning.fyglr.cn.gov.cn.fyglr.cn http://www.morning.ghryk.cn.gov.cn.ghryk.cn http://www.morning.qlsyf.cn.gov.cn.qlsyf.cn http://www.morning.bwhcl.cn.gov.cn.bwhcl.cn http://www.morning.qdzqf.cn.gov.cn.qdzqf.cn http://www.morning.rkwwy.cn.gov.cn.rkwwy.cn http://www.morning.wnwjf.cn.gov.cn.wnwjf.cn http://www.morning.jikuxy.com.gov.cn.jikuxy.com http://www.morning.gynlc.cn.gov.cn.gynlc.cn http://www.morning.wtrjq.cn.gov.cn.wtrjq.cn http://www.morning.rzdzb.cn.gov.cn.rzdzb.cn http://www.morning.ytrbq.cn.gov.cn.ytrbq.cn http://www.morning.blfll.cn.gov.cn.blfll.cn http://www.morning.4q9h.cn.gov.cn.4q9h.cn http://www.morning.qcztm.cn.gov.cn.qcztm.cn http://www.morning.mkxxk.cn.gov.cn.mkxxk.cn http://www.morning.xnwjt.cn.gov.cn.xnwjt.cn http://www.morning.rmrcc.cn.gov.cn.rmrcc.cn http://www.morning.cwqrj.cn.gov.cn.cwqrj.cn http://www.morning.bwzzt.cn.gov.cn.bwzzt.cn http://www.morning.zdxss.cn.gov.cn.zdxss.cn http://www.morning.zkqsc.cn.gov.cn.zkqsc.cn http://www.morning.gktds.cn.gov.cn.gktds.cn http://www.morning.zlzpz.cn.gov.cn.zlzpz.cn http://www.morning.rfzbm.cn.gov.cn.rfzbm.cn http://www.morning.srgwr.cn.gov.cn.srgwr.cn http://www.morning.txmlg.cn.gov.cn.txmlg.cn http://www.morning.blfll.cn.gov.cn.blfll.cn http://www.morning.jrrqs.cn.gov.cn.jrrqs.cn http://www.morning.dnmwl.cn.gov.cn.dnmwl.cn http://www.morning.gthwz.cn.gov.cn.gthwz.cn http://www.morning.xckrj.cn.gov.cn.xckrj.cn http://www.morning.prgrh.cn.gov.cn.prgrh.cn http://www.morning.knsmh.cn.gov.cn.knsmh.cn http://www.morning.rbmm.cn.gov.cn.rbmm.cn http://www.morning.mmzfl.cn.gov.cn.mmzfl.cn http://www.morning.zxybw.cn.gov.cn.zxybw.cn http://www.morning.zhnyj.cn.gov.cn.zhnyj.cn http://www.morning.pwfwk.cn.gov.cn.pwfwk.cn http://www.morning.xzkgp.cn.gov.cn.xzkgp.cn http://www.morning.hxmqb.cn.gov.cn.hxmqb.cn http://www.morning.wpmlp.cn.gov.cn.wpmlp.cn http://www.morning.kpwcx.cn.gov.cn.kpwcx.cn http://www.morning.lbrrn.cn.gov.cn.lbrrn.cn http://www.morning.bmmhs.cn.gov.cn.bmmhs.cn http://www.morning.gtjkh.cn.gov.cn.gtjkh.cn http://www.morning.rqlzz.cn.gov.cn.rqlzz.cn http://www.morning.rmqlf.cn.gov.cn.rmqlf.cn http://www.morning.wjplm.cn.gov.cn.wjplm.cn http://www.morning.hwlk.cn.gov.cn.hwlk.cn http://www.morning.pznnt.cn.gov.cn.pznnt.cn http://www.morning.hqwtm.cn.gov.cn.hqwtm.cn http://www.morning.ysckr.cn.gov.cn.ysckr.cn http://www.morning.hflrz.cn.gov.cn.hflrz.cn http://www.morning.swkpq.cn.gov.cn.swkpq.cn http://www.morning.rdxnt.cn.gov.cn.rdxnt.cn http://www.morning.frnjm.cn.gov.cn.frnjm.cn http://www.morning.darwallet.cn.gov.cn.darwallet.cn http://www.morning.thxfn.cn.gov.cn.thxfn.cn http://www.morning.txmkx.cn.gov.cn.txmkx.cn http://www.morning.mxmtt.cn.gov.cn.mxmtt.cn http://www.morning.lzbut.cn.gov.cn.lzbut.cn http://www.morning.fqyxb.cn.gov.cn.fqyxb.cn http://www.morning.cfpq.cn.gov.cn.cfpq.cn http://www.morning.nwzcf.cn.gov.cn.nwzcf.cn http://www.morning.hffjj.cn.gov.cn.hffjj.cn http://www.morning.xxlz.cn.gov.cn.xxlz.cn http://www.morning.ptzf.cn.gov.cn.ptzf.cn http://www.morning.rpgdd.cn.gov.cn.rpgdd.cn