【c++笔记(二)侯捷老师课程】带指针的类——string的实现

一、拷贝构造,拷贝复制

如果创建了带指针的类,那么一定要自己写拷贝函数,不能用编译器中的,因为编译器将指针复制,两个指针仍然指向同一个地址,不是真正意义上的拷贝。

一般字符串的设计

让字符串里面拥有一根指针,在需要内存时才去创建另外一个空间来放字符本身,字符有大有小,有种动态的感觉。

所以字符串的data应该是一个指针,指向字符。

1.String类的设计

class String
{
 public:
	String(const char* cstr = 0);			//构造函数,传进一根指向char类型指针,默认给他0
	String(const String& str);				//拷贝构造函数 -> 1
	String& operator= (const String& str);	//操作符重载,拷贝赋值函数 -> 2
	~String();								//析构函数 -> 3
	char* get_c_str() const { return m_data; }  //一般的成员函数,由于没有改变值,要加const

 private:
	char* m_data;
};

Big Three 三个特殊函数

拷贝构造函数:是一个构造函数,因为名称和类的名称相同,但是接收的参数是自己这种类型,所以叫拷贝构造函数

拷贝赋值函数:=右边也是自己

析构函数:以这个类做出的对象,当他死亡时,(离开作用域等,大括号是作用域),析构函数会被调用

几个函数的具体设计

1.构造函数

inline
String::String(const char* cstr = 0)//拷贝构造函数,默认初始值为0,即若没有则为0
{
	if (cstr)   //传进来的不为空
	{
		m_data = new char[strlen(cstr) + 1]; //分配的空间有多大呢?传进来的长度+1(结束符)
		strcpy(m_data, cstr);       //把传进来的值拷贝到刚刚分配的空间
	}
	else //未指定初值
	{
		m_data = new char[1];    //分配一块内存
		*m_data = '\0';          //准备一个字符放结束符
	}
}

调用示例

{
    String s1();
    String s2("hello");
  //大括号是作用域哦!!!
    String* p = new String("hello");
    delete p;
}

2.析构函数

对象死亡的前一刻,释放内存,因为之前动态分配了一块内存,需要释放,不然会造成内存泄漏。

inline
String::~String()//析构函数
{
	delete[] m_data;
}

一个带指针的类必须有拷贝构造和拷贝赋值函数!!!

原因:例如 b=a ,a和b中的data均为指向字符串的地址,把a中的data赋值给b,那么a和b指向同一块。(浅拷贝)

          然而我们希望的是赋值之后,两端需要分别有相同内容(深拷贝)。

          浅拷贝后,b端的内容没有指针指着,会造成内存泄漏。

3.拷贝构造函数(深拷贝)

此处,直接取另一个object的private data,因为兄弟之间互为friend

inline
String ::String(const String& str)
{
    m_data = new char [ strlen(str.m_data) + 1 ];//分配足够的空间容纳蓝本,然后把内容拷贝过去 
    strcpy(m_data,str.m_data);
}
{
    String s1("hello");//下面两句话的意思完全相同,写法却不一样
    String s2(s1);//以s1为蓝本(初值)创建一个s2
    String s2=s1;//把s1赋值到s2身上,注意此时s2也是一个新创建出的对象,需要调用构造函数
}

4.拷贝赋值函数

把右边的赋值给左边,先把左边清空,再创建出和右边一样大的空间,最后将右边的拷贝到左边

例如 s2=s1,赋值操作符作用在s2身上

       (1)检测自我赋值,功力深厚,大家风范

               检测是不是自己赋给自己,如果是,则后面都不做了,直接返回。

               必须写!!!若不写,释放本身内存空间后,要去看右边长度,然而右边已经不存在了。

               自我赋值不仅为了效率,也为了正确性!

       (2)s2先杀掉自己(delete)

       (3)分配内存

      (4)把字符串拷贝进去

inline
String& String::operator=(const String& str)//拷贝赋值,这里有个隐藏的第一参数this
{
	if (this == &str)//&在对象前面故这里是取地址,得到的是一根指针!!!不是引用(&在类型后面)
		return *this;
	delete[] m_data;
	m_data = new char[strlen(str.m_data) + 1];
	strcpy(m_data, str.m_data);

	return *this;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值