C++ 自己动手简单实现字符串String类

  • Post author:
  • Post category:其他


实现一个自己的String类是一道考验C++基础知识的好题。能够准确无误地编写出String类的构造函数、拷贝构造函数、赋值函数和析构函数的面试者至少已经具备了C++基本功的60%以上!

在这个类中包括了指针类成员变量m_pData,当类中包括指针类成员变量时,一定要重载其拷贝构造函数、赋值函数和析构函数,这既是对C++程序员的基本要求,也是《Effective C++》中特别强调的条款。

仔细学习这个类,特别注意加注释的得分点和加分点的意义,这样就具备了60%以上的C++基本功!

至少要能实现以下:构造函数,析构函数,拷贝构造函数(copy constructor),重载赋值操作符(copy assignment operator)。

String.h代码如下,

#pragma once
#pragma warning(disable:4996)
#include<iostream>
using namespace std;

class String
{
public:
	String();
	String(const char* pStr);
	String(const String& rhs);
	String& operator=(const String& rhs);
	~String();

	char operator[](int i) const;

	int size() const;
	char* c_str() const;
private:
	char* m_pData;
	friend ostream& operator<<(ostream& out, String& s);
	friend istream& operator>>(istream& in, String& s);
};

String.cpp代码如下,

#include "String.h"

String::String() : m_pData(new char[1])
{
	*m_pData = '\0';
}

String::String(const char * pStr)
{
	if (!pStr)
	{
		m_pData = new char[1];
		*m_pData = '\0';
	}
	else
	{
		int nLen = strlen(pStr);
		m_pData = new char[nLen + 1];
		strcpy(m_pData, pStr);
	}
}

String::String(const String & rhs)
{
	int nLen = strlen(rhs.m_pData);
	m_pData = new char[nLen + 1];
	strcpy(m_pData, rhs.m_pData);
}

String & String::operator=(const String & rhs)
{
	if (&rhs != this)
	{
		if(m_pData)
			delete[] m_pData;
		int nLen = strlen(rhs.m_pData);
		m_pData = new char[nLen + 1];
		strcpy(m_pData, rhs.m_pData);
	}
	return *this;
}


String::~String()
{
	if (m_pData)
	{
		delete[] m_pData;
	}
}

char String::operator[](int i) const
{
	int nLen = strlen(m_pData) - 1;
	if (i > nLen)
	{
		return '\0';
	}
	else
	{
		return m_pData[i];
	}
}

int String::size() const
{
	return strlen(m_pData);
}

char * String::c_str() const
{
	return m_pData;
}

ostream & operator<<(ostream & out, String & s)
{
	out << s.m_pData;
	return out;
}

istream & operator >> (istream & in, String & s)
{
	// TODO: insert return statement here
	char p[50];
	in.getline(p, 50);
	s = p;
	return in;
}

main.cpp代码如下,

#include "String.h"

int main(int argc, char** argv)
{
	String str3;
	String str1 = "man";
	String str2("shou");
	char ch = str1[2];
	//str1[2] = 'p';
	str3 = str1;
	cout << ch << endl;
	cout << str1 << endl;
	cout << str2 << endl;
	cout << str3 << endl;
	system("pause");
	return 0;
}

注意,String类的实现是用的深拷贝,如果用浅拷贝,当释放空间会把有用的空间释放掉,因为每次函数完成后会调用析构函数。

  • 深拷贝,给要拷贝构造的对象重新分配空间。
  • 浅拷贝,是对对象的简单拷贝,让几个指针都指向同一块地址空间,在释放这段空间的时候会产生“对已释放的空间再次释放”,导致程序中断。

上面是老版本的拷贝构造函数和重载赋值操作符的实现方式。有几点需要注意,判断自己赋值给自己 和 异常安全性。老版本的拷贝构造函数的实现,new的时候有可能会抛出异常。现代方法是通过使用

swap函数

简化方法。

使用swap的拷贝构造函数,通过swap将临时变量rhs中的数据保存到了data_中,同时data_中的数据拷贝到了临时变量中,在函数返回时会被自动释放。

代码修改如下,

String::String(const String & rhs)
{
	/*int nLen = strlen(rhs.m_pData);
	m_pData = new char[nLen + 1];
	strcpy(m_pData, rhs.m_pData);*/
	std::swap(m_pData, rhs.m_pData);
}

String & String::operator=(const String & rhs)
{
	/*if (&rhs != this)
	{
		if(m_pData)
			delete[] m_pData;
		int nLen = strlen(rhs.m_pData);
		m_pData = new char[nLen + 1];
		strcpy(m_pData, rhs.m_pData);
	}*/
	std::swap(m_pData, rhs.m_pData);
	return *this;
}



版权声明:本文为sinat_34715587原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。