C++拷贝构造函数(复制构造函数)

合集下载

测验1

测验1

一、单选题1.每个类()构造函数A. 只能有一个B. 只可有私有的C. 可以有多个D. 只可有缺省的2.已知类A中的一个成员函数的说明如下:void Set(A &a);则该函数的参数“A &a”的含义是( )A. 指向A的指针为aB. 将变量a的地址赋给类AC. 类A对象引用a用作函数的形参D. 变量A与a按位与后作函数参数3.假定AB为一个类,则执行AB x;语句时将自动调用该类的( )A. 有参构造函数B. 无参构造函数C. 拷贝构造函数D. 赋值构造函数4.拷贝(复制)构造函数的作用是A. 进行数据类型的转换B. 用对象调用成员函数C. 用对象初始化对象D. 用一般类型的数据初始化对象5.下列关于析构函数的描述中,错误的是( )A. 类中有且仅有一个析构函数B. 析构函数可以有形参C. 析构函数没有函数类型D. 析构函数在对象消失时被自动执行6.下列对类的构造函数和析构函数的描述中,正确的是( )A. 构造函数可以重载,析构函数不能B. 构造函数不能重载,析构函数可以C. 构造函数可以重载,析构函数也可以重载D. 构造函数不能重载,析构函数也不能重载7.假定MyClass为一个类,那么下列的函数说明中,( )为该类的析构函数.A. void ~MyClass();B. ~MyClass(int n);C. MyClass();D. ~MyClass();8.为了使类中的成员不能被类的对象通过成员操作符访问,则不能把该成员的访问权限定义为A. publicB. protectedC. privateD. static9.下列对与拷贝构造函数的描述中,正确的( )A. 在C++中,如果不自定义类的拷贝构造函数,则每个类都有默认的拷贝构造函数B. 必须为每个类定义拷贝初始化构造函数C. 如果要使用拷贝构造函数,则必须在类中显示进行定义D. 定义拷贝构造函数则无须定义构造函数10.对于下面定义的类MyClass,在函数f()中将对象成员n的值修改为50的语句(划线处)应该是( )class MyClass{public:MyClass(int x){n=x;}void SetValue(int n1){n=n1;}private:int n;};int f(){MyClass *ptr=new MyClass(45);__________;}A. MyClass(50)B. SetValue(50)C. ptr - > SetValue(50)D. ptr - > n=50二、填空题1. ______运算符对指定类型对象动态分配内存并返回该类型的指针。

详解C++中构造函数,拷贝构造函数和赋值函数的区别和实现

详解C++中构造函数,拷贝构造函数和赋值函数的区别和实现

详解C++中构造函数,拷贝构造函数和赋值函数的区别和实现C++中⼀般创建对象,拷贝或赋值的⽅式有构造函数,拷贝构造函数,赋值函数这三种⽅法。

下⾯就详细⽐较下三者之间的区别以及它们的具体实现1.构造函数构造函数是⼀种特殊的类成员函数,是当创建⼀个类的对象时,它被调⽤来对类的数据成员进⾏初始化和分配内存。

(构造函数的命名必须和类名完全相同)⾸先说⼀下⼀个C++的空类,编译器会加⼊哪些默认的成员函数默认构造函数和拷贝构造函数析构函数赋值函数(赋值运算符)取值函数**即使程序没定义任何成员,编译器也会插⼊以上的函数!注意:构造函数可以被重载,可以多个,可以带参数;析构函数只有⼀个,不能被重载,不带参数⽽默认构造函数没有参数,它什么也不做。

当没有重载⽆参构造函数时,A a就是通过默认构造函数来创建⼀个对象下⾯代码为构造函数重载的实现<span style="font-size:14px;">class A{int m_i;Public:A(){Cout<<”⽆参构造函数”<<endl;}A(int i):m_i(i) {} //初始化列表}</span>2.拷贝构造函数拷贝构造函数是C++独有的,它是⼀种特殊的构造函数,⽤基于同⼀类的⼀个对象构造和初始化另⼀个对象。

当没有重载拷贝构造函数时,通过默认拷贝构造函数来创建⼀个对象A a;A b(a);A b=a; 都是拷贝构造函数来创建对象b强调:这⾥b对象是不存在的,是⽤a 对象来构造和初始化b的!!先说下什么时候拷贝构造函数会被调⽤:在C++中,3种对象需要复制,此时拷贝构造函数会被调⽤1. 1)⼀个对象以值传递的⽅式传⼊函数体2. 2)⼀个对象以值传递的⽅式从函数返回3. 3)⼀个对象需要通过另⼀个对象进⾏初始化什么时候编译器会⽣成默认的拷贝构造函数:1. 1)如果⽤户没有⾃定义拷贝构造函数,并且在代码中使⽤到了拷贝构造函数,编译器就会⽣成默认的拷贝构造函数。

(完整版)拷贝构造函数

(完整版)拷贝构造函数
}
};
//全局函数
CExample g_Fun()
{
CExample temp(0);
return temp;
}
int main()
{
g_Fun();
return 0;
}
当g_Fun()函数执行到return时,会产生以下几个重要步骤:
(1). 先会产生一个临时变量,就叫XXXX吧。
(2). 然后调用拷贝构造函数把temp的值给XXXX。整个这两个步骤有点像:CExample XXXX(temp);(3). 在函数执行到最后先析构temp局部变量。
class CExample {
private:
int a;
public:
//构造函数
CExample(int b)
{ a = b;}
//拷贝构造函数
CExample(const CExample& C)
{
a = C.a;
}
//一般函数
void Show ()
{
cout<<a<<endl;
}
};
int main()
a = C.a;
cout<<"copy"<<endl;
}
//析构函数
~CExample()
{
cout<< "delete: "<<a<<endl;
}
void Show ()
{
cout<<a<<endl;
}
};
//全局函数,传入的是对象
void g_Fun(CExample C)

c++ string类的常用方法

c++ string类的常用方法

c++ string类的常用方法一、C++ string类的常用方法1、string类的构造函数string() // 构造空串string(const char* s) // 把null结尾的字符串s拷贝到字符串中string(const string& str) // 拷贝构造函数,复制str到此串string(char c, int n) // 用n个字符c构造串string(const char* s, int n) // 拷贝字符数组中前n个字符2、string类的成员函数2.1 长度控制函数int size() const; // 返回字符串的长度int length() const; // 返回字符串的长度,等价于size()void resize(int n, char c); // 改变字符串长度,如果n 大于原来的长度,用字符c来填充2.2 内容操作函数string& operator=(const char* s); // 赋值,把s的内容复制到字符串中string& assign(const char* s); // 赋值,把s的内容复制到字符串中string& append(const char* s); // 把字符串s添加到串尾string& append(const char* s, int n); // 把s前n个字符添加到串尾string& insert(int p0, const char* s); // 在p0位置上插入字符串sstring& erase(int p0, int n); // 删除p0开始,n个字符int find(const char* s, int pos=0); // 在pos之后查找子串s,返回子串s在原串中的起始位置int find(char c, int pos=0); // 从pos开始查找字符c,返回字符c在原串中的位置int rfind(const char* substr,int pos=npos); // 从pos开始向前查找子串substr,返回子串substr在原串中的起始位置int rfind(char c, int pos=npos); // 从pos开始向前查找字符c,返回字符c在原串中的位置string substr(int pos, int n); // 返回串pos 位置开始,长度为n的子串2.3 字符串比较函数int compare(const char* s); // 比较原串和sint compare(int p0, int n, const char* s); // 比较串中p0开始,n个字符的子串和s2.4 数据访问函数char& operator[](int i); // 返回串中第i个字符的引用const char& operator[](int i) const; // 返回串中第i个字符的引用const char* c_str() const; // 返回字符串以null结尾的字符串2.5 输入输出函数ostream& operator<<(ostream& os, const string& str); // 输出字符串istream& operator>>(istream& is, string& str); // 输入字符串。

C++拷贝(复制)构造函数详解

C++拷贝(复制)构造函数详解

C++拷贝(复制)构造函数详解⼀. 什么是拷贝构造函数⾸先对于普通类型的对象来说,它们之间的复制是很简单的,例如:[c-sharp]1. int a = 100;2. int b = a;⽽类对象与普通对象不同,类对象内部结构⼀般较为复杂,存在各种成员变量。

下⾯看⼀个类对象拷贝的简单例⼦。

[c-sharp]1. #include <iostream>2. using namespace std;3.4. class CExample {5. private:6. int a;7. public:8. //构造函数9. CExample(int b)10. { a = b;}11.12. //⼀般函数13. void Show ()14. {15. cout<<a<<endl;16. }17. };18.19. int main()20. {21. CExample A(100);22. CExample B = A; //注意这⾥的对象初始化要调⽤拷贝构造函数,⽽⾮赋值23. B.Show ();24. return 0;25. }运⾏程序,屏幕输出100。

从以上代码的运⾏结果可以看出,系统为对象 B 分配了内存并完成了与对象 A 的复制过程。

就类对象⽽⾔,相同类型的类对象是通过拷贝构造函数来完成整个复制过程的。

下⾯举例说明拷贝构造函数的⼯作过程。

[c-sharp]1. #include <iostream>2. using namespace std;3.4. class CExample {5. private:6. int a;7. public:8. //构造函数9. CExample(int b)10. { a = b;}11.12. //拷贝构造函数13. CExample(const CExample& C)14. {15. a = C.a;16. }17.18. //⼀般函数19. void Show ()20. {21. cout<<a<<endl;22. }23. };24.25. int main()26. {27. CExample A(100);28. CExample B = A; // CExample B(A); 也是⼀样的29. B.Show ();30. return 0;31. }CExample(const CExample& C) 就是我们⾃定义的拷贝构造函数。

西安交通大学3月课程考试《面向对象程序设计(高起专)》作业考核试题

西安交通大学3月课程考试《面向对象程序设计(高起专)》作业考核试题
正确答案:D
31:不能通过派生类对象引用从私有基类继承过来的任何成员。( )
A:错误
B:正确
正确答案:B
32:对使用默认参数的构造函数,如果在类外定义构造函数,应该在定义构造函数时指定默认值( )。
A:错误
B:正确
正确答案:A
33:如果定义了一个类的对象数组,该数组有10个元素,则要调用10次构造函数来对每个元素初始化。( )。
A:错误
B:正确
正确答案:A
49:在用class定义一个类时,如果不加声明,数据成员和成员函数默认的访问权限是public。( )
A:错误
B:正确
正确答案:A
50:友元类必须被说明为公用成员。( 案:A
D:20和5
正确答案:C
15:关于运行时多态的下列描述中,()是错误的。
A:运行时多态是以虚函数为基础的;
B:运行时多态是在运行时确定所调用的函数代码的;
C:用基类指针或引用所标识的派生类对象来操作虚函数才能实现运行时多态;
D:运行时多态是在编译时确定操作函数的。
正确答案:D
16:下面是五条顺序出现的声明语句,非法的初始化语句是()。
B:x [a]
C:x-&gt;a
D:x.a
正确答案:D
5:继承机制的作用是( )。
A:信息隐藏
B:数据封装
C:定义新类
D:数据抽象
正确答案:C
6:面向对象软件开发中使用的OOD表示( )。
A:面向对象分析
B:面向对象设计
C:面向对象语言
D:面向对象方法
正确答案:B

结构体拷贝构造函数

结构体拷贝构造函数

结构体拷贝构造函数
结构体是C语言中一种很常用的数据类型,它可以将不同类型的数据组合在一起,为使用者提供了很多方便。

对于结构体,有时当我们想要复制一个结构体时,就需要用到结构体拷贝构造函数,它可以将一个已经存在的结构体拷贝到新结构体中。

原来的结构体在构造函数中传入,该构造函数实现的功能是使用原始结构体的信息来构造一个新的结构体。

构造函数一般有两种,一种是深拷贝(deep copy),其中,拷贝函数会完全复制原来结构体里面的每个成员;另一种是浅拷贝(shallow copy),只会复制原来结构体里面的指针类型成员,而不会拷贝里面的值,也就是说,新的结构体里的指针类型成员,都指向原来的结构体里的成员。

对于深拷贝而言,不仅会拷贝结构体本身里面的成员,还会拷贝指针类型的成员;而对于浅拷贝,只会拷贝原来结构体里面的指针类型成员,指向的内容还是原来的结构体里的内容,而不会再开辟新的内存空间。

总之,结构体拷贝构造函数可以将一个已有的结构体拷贝到一个新的结构体中,数据会以浅拷贝或者深拷贝的方式进行复制,让用户更方便地实现数据复制。

c++中拷贝构造函数,浅拷贝和深拷贝的区别,以及移动构造函数总结

c++中拷贝构造函数,浅拷贝和深拷贝的区别,以及移动构造函数总结

c++中拷贝构造函数,浅拷贝和深拷贝的区别,以及移动构造函数总结⼀、构造函数、浅拷贝和深拷贝在C++提供了⼀种特殊的构造函数,称为拷贝构造函数。

拷贝构造函数具有⼀般构造函数的所有特性,其作⽤是使⽤⼀个已经存在的对象(由拷贝构造函数的参数指定的对象)去初始化⼀个新的同类对象,即完成本类对象的复制。

程序员如果没有定义拷贝构造函数,系统会⾃动⽣成⼀个默认的拷贝构造函数,其功能是把已存在的每个数据成员都复制到新对象中。

程序员定义拷贝构造函数时,⼀般形式: 类名(类名 & 对象){}拷贝构造函数在三种情况下会被⾃动调⽤(1)⽤⼀个对象去初始化⼀个同类的对象 XX B(A) (2) XX aa = a,当⼀个新对象被定义的时候,即便这个时候是使⽤了'='运算符,它真实调⽤的是初始化函数copy constructor,⽽不是调⽤copy assignment operator去进⾏赋值操作。

;(3)如果函数的形参是对象,进⾏形参和实参结合时,调⽤拷贝构造函数。

f(A);(4)如果函数的返回值是对象,返回主调函数时,调⽤拷贝构造函数。

XX B=g();其中默认的拷贝构造函数是浅拷贝。

当类的数据成员有指针类型是,假设同类对象A初始化B,A和B对象使⽤同⼀内存区域。

在撤销对象时,导致对这⼀内存的两次释放,也就是说浅层复制:只复制指向对象的指针,⽽不复制引⽤对象本⾝。

这时候要求程序员编制拷贝构造函数,使对象B的指针指向另外的内存区域,这叫深拷贝,深层复制:复制引⽤对象本⾝。

⼆、移动构造函数右值引⽤,临时值,如果是临时值,不调⽤深拷贝,⽽是移动构造函数(move construct),来提升性能。

#include<iostream>using namespace std;class Test{public:Test() :x(0){cout << "构造函数 this = " << this << endl;}Test(int x) :x(x){cout << "构造函数 this = " << this << endl;}Test(const Test& another) :x(another.x){cout << "拷贝构造函数 this = " << this << " from " << &another << endl;}Test(const Test&& another) : x(another.x){cout << "移动构造函数 this = " << this<< " from " << &another << endl;}~Test(){cout << "析构函数 this = " << this << endl;}friend ostream& operator<<(ostream& out, const Test &t);private:int x;};//运算符重载ostream& operator<<(ostream& out, const Test &t){out << "&t = " << &t << ",x = " << t.x;return out;}Test maketest(){Test x(4);cout << "hell" << endl;return x;}int main(){//测试拷贝构造函数Test test(3);cout << test << endl;Test test2(test);cout << test2 << endl;cout << endl;//测试移动构造函数Test first = maketest();//有⼀个临时对象,cout << first << endl;cout << endl;system("pause");}//测试移动构造函数1Test first = maketest();//有⼀个临时对象,/*测试1结果分析:正常情况下直接调⽤拷贝构造函数,如果定义了移动构造函数,则直接调⽤移动构造函数。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

有的、已经存在的数据创建出一份新的数据,最终的结果是多了一份相同的数据。

例如,将Word 文档拷贝到U盘去复印店打印,将D 盘的图片拷贝到桌面以方便浏览,将重要的文件上传到百度网盘以防止丢失等,都是「创建一份新数据」的意思。

在C++ 中,拷贝并没有脱离它本来的含义,只是将这个含义进行了“特化”,是指用已经存在的对象创建出一个新的对象。

从本质上讲,对象也是一份数据,因为它会占用内存。

严格来说,对象的创建包括两个阶段,首先要分配内存空间,然后再进行初始化:
∙分配内存很好理解,就是在堆区、栈区或者全局数据区留出足够多的字节。

这个时候的内存还比较“原始”,没有被“教化”,它所包含的数据一般是零值或者随机值,没有实际的意义。

∙初始化就是首次对内存赋值,让它的数据有意义。

注意是首次赋值,再次赋值不叫初始化。

初始化的时候还可以为对象分配其他的资源(打开文件、连接网络、动态分配内存等),或者提前进行一些计算(根据价格和数量计算出总价、根据长度和宽度计算出矩形的面积等)等。

说白了,初始化就是调用构造函数。

很明显,这里所说的拷贝是在初始化阶段进行的,也就是用其它对象的数据来初始化新对象的内存。

那么,如何用拷贝的方式来初始化一个对象呢?其实这样的例子比比皆是,string 类就是一个典型的例子。

1.#include<iostream>
2.#include<string>
ing namespace std;
4.
5.void func(string str){
6.cout<<str<<endl;
7.}
8.
9.int main(){
10.string s1 ="";
11.string s2(s1);
12.string s3 = s1;
13.string s4 = s1 +" "+ s2;
14.func(s1);
15.cout<<s1<<endl<<s2<<endl<<s3<<endl<<s4<<endl;
16.
17.return0;
18.}
运行结果:

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<iostream>
2.#include<string>
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."<<endl;
26.}
27.
28.void Student::display(){
29.cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<endl;
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++深拷贝和浅拷贝》一节中深入讲解。

相关文档
最新文档