当前位置:   article > 正文

(P15)构造函数与析构函数:深拷贝与浅拷贝,赋值操作,禁止拷贝,空类默认产生的成员_c++ 浅拷贝和深拷贝 禁用拷贝

c++ 浅拷贝和深拷贝 禁用拷贝

1.深拷贝与浅拷贝,赋值操作,禁止拷贝

  • eg:15cpp\15cpp\15cpp\01.cpp
#include "String.h"

int main(void)
{

	//深拷贝与浅拷贝
	String s1("AAA");
	s1.Display();
	String s2 = s1;		//若自己没有实现一个拷贝构造函数, 则调用系统提供的默认的拷贝构造函数
						// 系统提供的默认拷贝构造函数实施的是浅拷贝,等价于s2.str_ = s1.str_,
						//如果还有其他成员,就是逐成员赋值
						//这里s2中的str_指针与s1中的str_指针指向同一块内存,在构造s2对象的时候没有分配自己的内存,
						//两个对象指向同一块内存
						//当2个对象生存周期结束时,都要调用析构函数,同一块内存被释放2次,因而出现了运行时错误
						//解决办法:不使用系统提供的默认的拷贝构造函数,自己实现一个拷贝构造函数

	//赋值运算
	String s3;
	s3.Display();
	s3 = s2;			// 调用等号运算符
						// 系统提供的默认等号运算符实施的是浅拷贝,等价于s3.str_ = s2.str_;如果还有其他成员,就是逐成员赋值,也会出现一个对象被销毁2次,
						//所以提供自己的等号运算符
						// s3.operator=(s2);

	//禁止拷贝
	// 要让对象是独一无二的,我们要禁止拷贝
	// 方法是将拷贝构造函数与=运算符声明为私有,并且不提供它们的实现
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 类声明及定义
    15cpp\15cpp\15cpp\String.h
#ifndef _STRING_H_
#define _STRING_H_

class String
{
public:
	String(char* str="");//默认参数是空串
	~String();
	String(const String& other);
	String& operator=(const String& other);

	

	void Display();

private:
	char* AllocAndCpy(char* str);
	
	char* str_;//类内部涉及到动态内存分配,则使用深拷贝,除了共享内存

	//禁止拷贝的做法:若是独一无二的对象,独一无二的对象不允许拷贝,将声明以及实现都注释掉,所以会导致编译出错
	// String(const String& other);
	// String& operator=(const String& other);
};

#endif // _STRING_H_

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

15cpp\15cpp\15cpp\String.cpp

#include "String.h"

#include <cstring>//等价于#include <string.h>
#include <iostream>
using namespace std;

String::String(char* str/* = */)
{
	str_ = AllocAndCpy(str);
}

String::~String()
{
	delete[] str_;
}

//错误的浅拷贝做法:自己实现一个拷贝构造函数
String::String(const String& other) : str_(other.str_)
{

}

//深拷贝做法:自己实现一个拷贝构造函数
String::String(const String& other)
{
	str_ = AllocAndCpy(other.str_);
}

//返回String&:减少拷贝构造函数的调用,返回自身的对象
String& String::operator =(const String &other)
{
	//对象赋值给自身
	if (this == &other)
		return *this;
	
	//等号运算符意味着左边的对象已经存在了,所以先销毁
	//而拷贝构造函数说明对象还不存在,所以不用先销毁
	delete[] str_;
	str_ = AllocAndCpy(other.str_);
	return *this;
}

char* String::AllocAndCpy(char* str)
{
	int len = strlen(str) + 1;//分配这么长的字符串
	char* tmp = new char[len];//分配空间
	memset(tmp, 0, len);
	strcpy(tmp, str);
	return tmp;
}

void String::Display()
{
	cout<<str_<<endl;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 测试
    在这里插入图片描述
    禁止拷贝
    在这里插入图片描述

2.空类默认产生的成员

  • eg:15cpp\15cpp\15cpp\02.cpp
#include <iostream>
using namespace std;

class Empty
{
public:
	Empty* operator&()
	{
		cout<<"AAAA"<<endl;
		return this;
	}

	//const成员函数
	const Empty* operator&() const
	{
		cout<<"BBBB"<<endl;
		return this;
	}
};

int main(void)
{
	//p的指针和取地址e是相同的
	Empty e;
	Empty* p = &e;		//这里会调用取地址运算符,等价于e.operator&()

	const Empty e2;
	const Empty* p2 = &e2;//const在*左边,表示*p2是一个常量
							//const在*右边,表示p2是一个常量
							//这里的&取地址运算符,进入到了const Empty* operator&() const

	cout<<sizeof(Empty)<<endl;

	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 测试:
    空类的大小是1个字节,当实例化对象时,会分配内存,若没有任何一个字节,如何实例化对象呢?
    会依据最小原则,编译器会生成一个字节的空间
    在这里插入图片描述
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/501779
推荐阅读
相关标签
  

闽ICP备14008679号