【C++】类和对象(5)--拷贝构造函数

目录

一 概念

二 拷贝构造函数特性

1. 重载形式

2. 参数原则

3 默认拷贝函数

三 拷贝构造函数的实现


一 概念

在创建对象时,可否创建一个与已存在对象一某一样的新对象呢?

class Date
{
public:
       Date(int year = 1900, int month = 1, int day = 1)//默认构造函数
       {
              _year = year;
              _month = month;
              _day = day;
       }

       
       void Print()
       {
              cout << _year << "/" << _month << "/" << _day << endl;
       }

private:
       int _year;
       int _month;
       int _day;
};


class Stack
{
public:
       Stack(size_t capacity = 3)
       {
              cout << "Stack(size_t capacity = 3)" << endl;

              _a = (int*)malloc(sizeof(int) * capacity);
              if (nullptr == _a)
              {
                      perror("malloc申请空间失败!!!");
              }

              _capacity = capacity;
              _top = 0;
       }

       ~Stack()
       {
              cout << "~Stack()" << endl;

              free(_a);
              _capacity = _top = 0;
              _a = nullptr;
       }

private:
       int* _a;
       int _capacity;
       int _top;
};


//值拷贝浅拷贝
void func1(Date d)//形参是实参拷贝
{
       d.Print();
}

void func2(Stack st)//这样拷贝这是不行的
{
       //...
}

int main()
{
       Date d1(2023, 10, 22);
       func1(d1);

       Stack st1;
       func2(st1);

       return 0;
}

 我们可以看到Date类就能传参 但是Stack类就不行, 这涉及到了浅拷贝, 深拷贝

如何解决?

规定, 自定义类型对象拷贝的时候, 调用一个函数, 这个函数就叫拷贝构造

拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存 在的类类型对象创建新对象时由编译器自动调用

拷贝构造函数通常用于:

• 通过使用另一个同类型的对象来初始化新创建的对象。

• 复制对象把它作为参数传递给函数。

• 复制对象,并从函数返回这个对象。
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)//默认构造函数
	{
		_year = year;
		_month = month;
		_day = day;
	}

private:
	int _year;
	int _month;
	int _day;
};


void func1(Date d)//调用拷贝构造 -->形参是实参的拷贝
{
	/*
	(1).d1对象传入形参时,会先会产生一个临时变量,就叫 d。
	(2).然后调用拷贝构造函数把d1的值给d。 整个这两个步骤有点像:Date d(d1);
	(3).等func1()执行完后, 析构掉 d 对象。
	*/
}

Date func2()
{
	Date d2(2023, 11, 20);
	return d2;//调用拷贝构造
	/*
	(1).先会产生一个临时变量,就叫XXXX吧。
	(2).然后调用拷贝构造函数把d2的值给XXXX。整个这两个步骤有点像:Date XXXX(d2);
	(3).在函数执行到最后先析构d2局部变量。
	(4).等func2()执行完后再析构掉XXXX对象。
	*/
}

int main()
{
	Date d1(2023, 10, 22);
	func1(d1);
	Date d3(d1); //调用拷贝构造
	Date d4 = d1;//调用拷贝构造
	return 0;
}

二 拷贝构造函数特性

拷贝构造函数也是特殊的成员函数,其特征如下:

1. 重载形式

拷贝构造函数是构造函数的一个重载形式。

class Date
{
public:
    Date(int year = 1900, int month = 1, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    // Date(const Date d)--> 错误写法:编译报错,会引发无穷递归
    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);//将d1拷贝给d2
    return 0;
}

2. 参数原则

拷贝构造函数的参数只有一个且必须是类类型对象的引用

使用传值方式编译器直接报错, 因为会引发无穷递归调用。

 

3 默认拷贝函数

若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按 字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝

前面已经说了Date类就用编译器生成的默认拷贝构造函数就可以了 不用显示定义构造函数了

注意:类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请 时,则拷贝构造函数是一定要写的,需要深度拷贝,否则就是浅拷贝

三 拷贝构造函数的实现

像栈 这些涉及到了资源的申请, 那就需要深度拷贝了

class Stack
{
public:
       Stack(size_t capacity = 3)
       {
              cout << "Stack(size_t capacity = 3)" << endl;

              _a = (int*)malloc(sizeof(int) * capacity);
              if (nullptr == _a)
              {
                      perror("malloc申请空间失败!!!");
              }

              _capacity = capacity;
              _top = 0;
       }

       // Stack st2(st1);
       Stack(const Stack& stt)
       {
              cout << " Stack(Stack& stt)" << endl;
              // 深拷贝
              _a = (int*)malloc(sizeof(int) * stt._capacity);
              if (_a == nullptr)
              {
                      perror("malloc fail");
                      exit(-1);
              }
              memcpy(_a, stt._a, sizeof(int) * stt._top);
              _top = stt._top;
              _capacity = stt._capacity;
       }

       ~Stack()
       {
              cout << "~Stack()" << endl;

              free(_a);
              _capacity = _top = 0;
              _a = nullptr;
       }

private:
       int* _a;
       int _capacity;
       int _top;
};

class MyQueue
{
       Stack _pushst;
       Stack _popst;
       int _size = 0;
};


void func2(Stack st)
{
       //...
}

int main()
{
       Stack st1;
       func2(st1);
       Stack st2(st1);

       MyQueue q1;
       MyQueue q2(q1);

       return 0;
}

总结:

Date 和 MyQueue 默认生成拷贝就可以用        

1、内置类型成员完成值拷贝        

2、自定义类型成员调用这个成员的拷贝构造        

Stack需要自己写拷贝构造,完成深拷贝   顺序表、链表、二叉树等等的类,都需要深拷贝 

本节难度比较简单, 但是对基础性要求较强, 对构造函数还有不太懂的朋友可以去我的博客:

【C++】类和对象(2)--构造函数-CSDN博客

继续加油!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值