拷贝构造函数

C++:拷贝构造函数&赋值运算符的重载函数

匿名 (未验证) 提交于 2019-12-02 23:00:14
拷贝构造函数 : 默认的拷贝构造函数 : 深拷贝&浅拷贝: 思考: 当对象中存在指针成员时,为什么需要自己实现拷贝构造函数?如果不,会出现怎样的问题? 看代码 : #include<iostream> class CGoods { public: CGoods(const char* name, double price, int amount)//带有三个参数的构造函数 { std::cout << this << " :CGoods::CGoods(char*,float,int)" << std::endl; mname = new char[strlen(name) + 1](); strcpy(mname, name); mprice = price; mamount = amount; } CGoods()//不带参数的构造函数 { std::cout << this << " :CGoods::CGoods()" << std::endl; mname = new char[1](); } private: char* mname; double mprice; int mamount; }; int main() { CGoods good1("car1", 10.1, 10); CGoods good2 = good1; return 0; } 程序运行结果:

Keithee Explorer

谁都会走 提交于 2019-12-01 21:54:07
本章学习如何控制类类型对象在拷贝、赋值、移动和销毁时应该做什么。 一个类定义五种特殊的成员函数来控制对象的拷贝、移动、赋值和销毁操作。他们分别是拷贝构造函数、拷贝赋值运算符、移动构造函数、移动赋值函数和析构函数。 拷贝、赋值与销毁 拷贝构造函数 如果构造函数的第一个参数是自身对象的引用,而且其他额外参数都有默认值,则该构造函数是拷贝构造函数。 12345 class {public: Foo(); Foo(const Foo&);} 拷贝构造函数会在几种情况下被隐式地使用,所以不应该是 explicit 。 合成拷贝构造函数 如果我们没有定义一个拷贝构造函数,则编译器会为我们定义一个。编译器将类内的每个非 static 成员拷贝到正在创建的对象中。对于类类型的成员,则使用其拷贝构造函数来拷贝。 123456789 class Sales_data{public: Sales_data(const Sales_data&);private: string bookNo; int units_sold; double revenue;} 现在我们可以理解直接初始化和拷贝初始化的真正区别了,也就是说直接初始化是一个构造函数参数匹配的过程,而拷贝初始化要求我们将右侧的运算对象拷贝到左侧的对象中去,有时候还要求类型转换。 拷贝初始化不仅发生在使用 = 运算符时,还发生在以下情况:

构造函数调用规则

让人想犯罪 __ 提交于 2019-11-30 15:52:36
首先我们知道只要创建一个类编译器会提供三个默认函数 1.默认构造函数 (无参,空实现) 2.默认析构函数(无参,空实现) 3.默认拷贝构造函数,对值属性进行拷贝 调用规则如下 1.如果我们定义有参构造函数,编译器不会提供默认构造函数,但提供默认拷贝构造函数 2.如果用户定义了拷贝构造函数,编译器将不会提供其他构造函数 1 #include<bits/stdc++.h> 2 using namespace std; 3 4 class person 5 { 6 public: 7 person() 8 { 9 puts("默认构造函数调用"); 10 } 11 12 person(const person &p) 13 { 14 m_age = p.m_age; 15 puts("拷贝构造函数调用"); 16 } 17 18 person(int age) 19 { 20 m_age = age; 21 puts("有参构造函数调用"); 22 } 23 24 ~person() 25 { 26 puts("析构函数调用"); 27 } 28 29 int m_age; 30 }; 31 32 void test() 33 { 34 person p; 35 p.m_age = 18; 36 person p2(p); 37 cout << p2.m_age << endl; 38

牛客 C++刷题day25

随声附和 提交于 2019-11-30 15:11:11
1.在一个对象未建立起来时通常用的是拷贝构造函数,而对象建立起来之后的复制拷贝就需要使用赋值运算符重载了。 拷贝构造函数形式如下: CExample(const CExample& C) 就是我们自定义的拷贝构造函数。可见,拷贝构造函数是一种 特殊的 构造函数 ,函数的名称必须和类名称一致,它必须的一个参数是本类型的一个 引用变量 。 调用场合有: 当函数的参数为类的对象时; 函数的返回值是类的对象; 对象需要通过另外一个对象进行初始化。 拷贝构造函数时默认浅拷贝,即只对新对象的值进行简单复制。而深拷贝则需要更为复杂的操作,简单赋值并不能解决问题。比如A中有int *p=new int(100)。 赋给B时则不能简单的B.p=A.p应该是需要在B中重新进行new操作。这就是深浅的区别。 还有一点,系统可以帮我们自动进行浅拷贝比如 CLASS A(B)。这样的操作。即使CLASS中没有拷贝构造函数的定义,我们也仍然可以达到目的。 2.在计算机中,表示汉字时,UTF-16是用2个字节,UTF-8是用三个字节。如果保存成文本文件,还需要标识,UTF-16占用两个字节,UTF-8占用三个字节。 来源: https://www.cnblogs.com/Tonarinototoro/p/11600765.html

C++类拷贝控制 深拷贝 浅拷贝

戏子无情 提交于 2019-11-30 10:38:43
普通类型对象之间的复制很简单,而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量,这篇文章将帮你理清C++类对象的拷贝方式 拷贝构造函数,拷贝赋值运算符 首先我们简单了解下默认的拷贝构造函数和拷贝赋值运算符 拷贝构造函数 第一个参数是自身类类型引用,其他参数都有默认值的构造函数就是拷贝构造函数 class Sales_data { public: Sales_data(); //默认构造函数 Sales_data(const Foo&); //默认拷贝构造函数 //... }; 拷贝构造函数用来初始化非引用类类型参数,所以 拷贝构造函数自己的参数必须是引用类型 (如果不是引用:为了调用拷贝构造函数,必须拷贝它的实参,为了拷贝实参,又需要调用拷贝构造函数,无限循环) 合成拷贝构造函数(默认) 和默认构造函数一样,编译器会帮你定义一个默认拷贝构造函数(如果你没有手动定义的话),不同的是,如果你定义了其他构造函数,编译器还是会给你合成一个拷贝构造函数 举个例子:Sales_data的合成拷贝构造函数等价于 class Sales_data { public: Sales_data(); Sales_data(const Sales_data&); private: std::string bookNo; int units_sold = 0; double

C++:Copy & Reference Count

馋奶兔 提交于 2019-11-30 03:33:10
浅拷贝、深拷贝 通常,我们会按如下方式书写拷贝构造函数: class LiF { public: LiF(int _lif = 0) : lif(_lif) {} // 默认构造函数 LiF(const LiF& l) : lif(l.lif) {} // 拷贝构造函数 private: int lif; }; 这是正确的。但是,如果数据成员包含指针类型的话,这种写法就很危险了。 class LiF { public: LiF() { lif = new int(0); } // 为lif动态分配内存 LiF(const LiF& l) : lif(l.lif) {} // 拷贝构造函数 ~LiF() { // 析构函数 delete lif; // 释放分配给lif的资源 lif = nullptr; // 置空 } private: int* lif; }; LiF l1; LiF l2(l1); // 程序结束析构l2时,程序将崩溃 在拷贝 l1 生成 l2 的时候,我们的构造函数只是简单的把 l1 的 lif 成员的值赋予了 l2 的 lif ,也就是说,它们保存的都是 l1 构造时分配的地址,当两者之中的某个对象被销毁时,构造函数正常执行,资源被释放,但之后如果另一个对象也被析构, lif 的资源就会被重复释放, lif 也就变成野指针。这种拷贝方式也称为 浅拷贝

C++:Special Member Functions

天大地大妈咪最大 提交于 2019-11-30 02:53:48
Special Member Functions 区别于定义类的行为的普通成员函数,类内有一类特殊的成员函数,它们负责类的 构造 、 拷贝 、 移动 、 销毁 。 构造函数 构造函数控制对象的初始化过程,具体来说,就是初始化对象的数据成员。构造函数的名字与类名相同,且没有返回值。构造函数也可以有 重载 ,重载区别于参数数量或参数类型。与其他成员函数不同的是,构造函数不能被声明为 const ,对象的常量属性是在构造函数完成初始化之后获得的。 默认构造函数 默认构造函数的工作是:如果在类内定义了成员的初始值,那么用初始值初始化成员;否则,默认初始化成员。 默认初始化是指定义变量时不赋予初始值时被赋予默认值的动作。定义于函数体外的内置类型如果没有被显式初始化,则赋值0;在函数体内定义的变量不会被初始化。 class LiF { public: LiF(int _lif = 0) { lif = _lif; } // 指定了lif的初值,这是一个默认构造函数 private: int lif; } LiF l; // 调用默认构造函数,此时l.lif值为0 再看下面这种情况: class LiF1 { public: LiF1(int _lif = 0) { lif = _lif; } int lif; }; class LiF2 { public: LiF1 lif1; }; LiF2

对象的构造与析构(一)

允我心安 提交于 2019-11-29 19:37:54
目录 1. 构造函数的定义 2. 构造函数的重载 3. 两个特殊的构造函数 4. 初始化列表的使用 1. 构造函数的定义 从程序设计的角度,类的对象只是变量, 在栈上和堆上创建对象时,成员变量初始为随机值;创建全局对象时,成员变量初始为0值。 C++中可以定义与类名相同的特殊成员函数,叫做构造函数 构造函数没有任何返回类型 类的构造函数在 对象定义时自动被调用 ,进行对象的初始化工作 对象的定义和声明是不同的 Test t1; //定义对象,为对象分配内存空间,并调用构造函数 extern Test t2; //声明对象,告诉编译器存在这样一个对象 2. 构造函数的重载 一个类中可以根据需要定义多个重载的构造函数 构造函数的重载遵循C++重载的规则 #include <stdio.h> class Test { public: Test() { printf("Test()\n"); } Test(int v) { printf("Test(int v), v = %d\n", v); } Test(int v1, int v2) { printf("Test(int v1, int v2), v1 = %d, v2 = %d\n", v1, v2); } }; int main() { Test t; //调用 Test() Test t1(1); //调用 Test(int v

C++类和对象(三)之拷贝构造函数

不想你离开。 提交于 2019-11-29 16:33:14
1.概念: 构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。 2.特征 拷贝构造函数是构造函数的一个重载形式。 拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。 若未显示定义,系统生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝我们叫做浅拷贝,或者值拷贝。 class Date { public: Date(int year = 1900, int month = 1, int day = 1) { _year = year; _month = month; _day = day; } Date(const 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; } 问:为什么传值会引起无限递归调用? 答: 因为传值调用时,形参是实参的一份拷贝。 看不懂需要更详细的请点击: C++拷贝构造函数的参数为什么必须使用引用 来源: https://blog.csdn.net

拷贝构造函数

a 夏天 提交于 2019-11-28 06:30:43
拷贝构造函数调用时机(用一个对象初始化另一个对象时) 赋值构造函数的四种调用场景(调用时机) 第1和第2个调用场景 #include "iostream" using namespace std; class AA { public: AA() //无参构造函数 默认构造函数 { cout<<"我是构造函数,自动被调用了"<<endl; } AA(int _a) //无参构造函数 默认构造函数 { a = _a; } AA( const AA &obj2)//拷贝构造函数 (也叫赋值构造函数) 红色部分是类本身的名字 { cout<<"我也是构造函数,我是通过另外一个对象obj2,来初始化我自己"<<endl; a = obj2.a + 10; } ~AA() { cout<<"我是析构函数,自动被调用了"<<endl; } void getA() { printf("a:%d \n", a); } protected: private: int a; }; //单独搭建一个舞台 void ObjPlay01() { AA a1; //变量定义 //赋值构造函数的第一个应用场景 (等号法) //用对象1 初始化 对象2 AA a2 = a1; //定义变量并初始化 //初始化法(等号法) a2 = a1; //用a1来=号给a2 编译器给我们提供的浅copy } 第二个应用场景 /