【C/C++】复制构造函数、深复制浅复制

常见问题

Q1. 下面代码的输出结果是( )?

 1 #include <iostream>
 2 using namespace std;
 3
 4 class MyClass
 5 {
 6 public:
 7     MyClass(int n) { number = n; }
 8     MyClass(const MyClass &other)
 9     {
10         number = other.number;
11         cout << "a ";
12     }
13 private:
14     int number;
15 };
16
17 void fun(MyClass p)
18 {
19     MyClass temp(p);
20 }
21
22 int main(void)
23 {
24     MyClass obj1(10), obj2(0);
25     MyClass obj3(obj1);
26     fun(obj3);
27     return 0;
28 }

A. a a a  B. a a a a  C. a a  D. a

Q2. 为什么拷贝构造函数的参数是一个引用,可以不是引用吗?

Q3. 什么是深复制?什么是浅复制?

复制构造函数

1. 复制构造函数

  只有单个形参,而且该形参是对本类类型对象的引用(常用const修饰),这样的构造函数称为复制构造函数(或拷贝构造函数)。与默认构造函数一样,复制构造函数可由编译器隐式调用。

  复制构造函数、赋值操作符和析构函数总称为复制控制。编译器自动实现这些操作,但类也可以定义自己的版本。

  如果类需要析构函数,则它也需要赋值操作符和复制构造函数,这是一个有用的经验法则。这个规则常称为三法则,指的是如果需要析构函数,则需要所有三个复制控制成员。

  通常,编译器合成的复制控制函数是非常精练的——它们只做必需的工作。但对某些类而言,依赖于默认定义会导致灾难。实现复制控制最困难的部分,往往在于识别何时需要覆盖默认版本。有一种特别常见的情况需要定义自己的复制控制成员:类具有指针成员。

2. 复制构造函数的作用

(1) 根据另一个同类型的对象初始化一个对象

  C++支持两种初始化形式:直接初始化和复制初始化。复制初始化使用=符号,而直接初始化将初始化式放在圆括号中。

1 string null_book1("9-999-99999-9"); // 直接初始化
2 string null_book2(null_book1); // 复制初始化
3 string null_book3 = null_book1; // 复制初始化
4 string null_book4 = "9-999-99999-9"; // 复制初始化 

  上述代码中,语句4为复制初始化,首先使用指定构造函数(接受一个C风格字符串形参的string构造函数)创建一个临时对象,然后用string复制构造函数将那个临时对象复制到正在创建的对象。

  但需要注意的是,很多编译器中,语句4的方式等价于语句1的方式。也就是说这些编译器做了优化,跳过了复制构造函数直接调用到普通的构造函数创建对象。

  注意下面的语句3不是复制构造函数:

1 string null_book1("9-999-99999-9");
2 string null_book2;
3 null_book2 = null_book1;

  语句2是调用string的默认构造函数创建一个空字符串对象,语句3是利用赋值运算符将null_book1赋值给null_book2。

(2) 复制一个对象,将它作为实参传给一个函数或从函数返回时复制一个对象

(3) 初始化顺序容器中的元素

(4) 根据元素初始化式列表初始化数组元素

3. 浅复制与深复制

时间: 2024-08-27 02:10:52

【C/C++】复制构造函数、深复制浅复制的相关文章

复制构造函数——深复制 浅复制

隐含的复制构造函数并不总是适用的,因为它完成的只是浅复制. 对象的浅复制 1 #include<iostream> 2 #include<cassert> 3 using namespace std; 4 class Point{ 5 public: 6 Point() :x(0), y(0)//默认构造函数 7 { 8 cout << "constructor1" << endl; 9 } 10 Point(int x, int y)

【C/C++学院】(6)构造函数/析构函数/拷贝构造函数/深copy浅copy

1.构造函数 类的初始化即为构造函数.也为:隐式的初始化. 构造函数在对象初始化的时候,自动被调用.隐式的调用. 构造函数分为三种:有参构造函数.无参构造函数.拷贝构造函数. 有参构造函数调用有三种:括号法.等号法.手工法. #include <iostream> using namespace std; class Test { private: int m_a; public: Test()//无参构造函数 { } Test(const Test &obj)//拷贝构造函数 { }

C++学习基础七——深复制与浅复制

一.深复制与浅复制基本知识 深复制和浅复制,又称为深拷贝和浅拷贝. 深复制和浅复制的区别如下图1所示: 图1 图1表示的是,定义一个类CDemo,包含int a和char *str两个成员变量, 当深复制时,A中的指针str与B中的指针str指向不同的地址,只是地址所指向的数据相同. 当浅复制时,A中的指针str与B中的指针str指向相同的地址. 1.浅复制:如果我们自己不实现复制构造函数,则C++会自动合成一个复制构造函数,又称为浅复制构造函数. 2.深复制:如果使用指针或者系统资源(如数据库

原型模式——浅复制与深复制

原型模式涉及一个浅复制和深复制的概念.原型模式可以简单理解为“复制”,但这个复制不是代码的复制.对同一个类,我们可以实例化new三次来“复制”,但如果在初始化的时候构造函数的执行很长,多次实例化就显得效率很低效了.那我们能否只实例化一次,然后“复制”呢? Test test1 = new Test(); Test test2 = test1; Test test3 = test1; 这样写吗?注意这是引用的复制,这实际上还是只有test1一个实例,test2.test3只是复制了其引用而已,如果

iOS 集合的深复制与浅复制

概念 对象拷贝有两种方式:浅复制和深复制.顾名思义,浅复制,并不拷贝对象本身,仅仅是拷贝指向对象的指针:深复制是直接拷贝整个对象内存到另一块内存中. 一图以蔽之 再简单些说:浅复制就是指针拷贝:深复制就是内容拷贝. 集合的浅复制 (shallow copy) 集合的浅复制有非常多种方法.当你进行浅复制时,会向原始的集合发送retain消息,引用计数加1,同时指针被拷贝到新的集合. 现在让我们看一些浅复制的例子: NSArray *shallowCopyArray = [someArray cop

深复制与浅复制

概念 对象拷贝有两种方式:浅复制和深复制.顾名思义,浅复制,并不拷贝对象本身,仅仅是拷贝指向对象的指针:深复制是直接拷贝整个对象内存到另一块内存中. 一图以蔽之 再简单些说:浅复制就是指针拷贝:深复制就是内容拷贝. 集合的浅复制 (shallow copy) 集合的浅复制有非常多种方法.当你进行浅复制时,会向原始的集合发送retain消息,引用计数加1,同时指针被拷贝到新的集合. 现在让我们看一些浅复制的例子: NSArray *shallowCopyArray = [someArray cop

关于深复制与浅复制

转自“红黑联盟”,网址:http://www.2cto.com/kf/201405/302273.html 第一.复制对象的基本概念 复制一个对象为副本,开辟一块新的内存来存储副本对象. 第二.如果一个对象想具备复制的功能,必须实现协议和协议 NSObject自带的常用的对象有:NSNumber.NSString.NSArray.NSDictionary.NSMutableArray.NSMutableDictionay.NSMutableString,copy产生的对象时不可变的,mutabl

JavaScript中对象的浅复制和深复制

在JavaScript中,如果要复制一个变量我们应该怎么做呢?下面这种做法是最简单的一种形式: //把a复制给b let a = 12; let b = a; 这种复制方法只能适用于基本类型,如果a是对象怎么办呢?我们先来看看上面的代码在内存中做了什么事: 声明了变量a = 12,栈内存会分配一块区域来存储,如上图所示.把a赋给b,会在栈中重新开辟一块区域来存储b,并且b的值就是a的值. 假如a是对象,内存做了什么事呢?来看下面的例子: let a = {}; let b = a; 如图所示,对

笔记十:复制构造函数、深拷贝、浅拷贝

复制构造函数 定义: 只有单个形参,而且该形参是对本类类型对象的引用(常用const修饰),这样的构造函数成为复制构造函数.复制构造函数可用于: 1.根据另一个同类型的对象显示或隐式初始化一个对象 2.复制一个对象,将它作为实参传递给一个函数 3.从函数返回时复制一个对象 4.初始化顺序容器中的元素 5.根据元素初始化列表初始化数组元素 --以上定义来自<C++ Primer 中文版 第4版> 浅拷贝/浅复制 第一条中,若一个自定义类对象已经初始化了,并且用该类去初始化另一个同类类型的对象,假