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