0
点赞
收藏
分享

微信扫一扫

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


文章目录

  • ​​1.深拷贝与浅拷贝,赋值操作,禁止拷贝​​
  • ​​2.空类默认产生的成员​​

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;
}

  • 类声明及定义
    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_

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;
}

  • 测试

    禁止拷贝

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个字节,当实例化对象时,会分配内存,若没有任何一个字节,如何实例化对象呢?
    会依据最小原则,编译器会生成一个字节的空间



举报

相关推荐

深拷贝与浅拷贝

0 条评论