拷贝构造
- 当类没有实现拷贝构造的时候,编译器会提供一个默认的拷贝构造
- 默认拷贝构造即内存拷贝(通过memcpy拷贝也就是浅拷贝)
- 当类提供了拷贝构造时,则调用提供的拷贝构造
拷贝构造的时机
- 对象传参, 比如调用void Test(ClassName buf)时形参需要传入ClassName的类对象,其实际上就是拷贝构造
- 使用对象构造对象, 比如下面的例子
ClassName obj1; // 默认无参构造函数
ClassName obj2(obj1); // 显式调用了拷贝构造
- 返回值返回类类型, 比如ClassName Test(); 被调用时会调用拷贝构造函数
匿名对象
- 返回类对象时
- 手动构造匿名对象, 比如ClassName().function(),通过ClassName()调用了无参构造函数并生成了匿名对象后调用了对象的function()方法
这里实现了一个完整的String工具类作为例子, 其使用了引用计数的方式
其主要功能如下:
- 拼接追加字符串
- 拷贝字符串
- 查询字符串
- 比较字符串
- 正向与逆向的子串查找
- 子串提取
- 格式化字符串
首先是头文件:
// CMyString.h
#ifndef _CSMYSTRING_H
#define _CSMYSTRING_H
class CMyString
{
public:
CMyString();
explicit CMyString(const char* sz);
explicit CMyString(char ch);
CMyString(const CMyString& obj);
~CMyString();
inline size_t GetLen() const
{
return(m_nLen);
}
inline const char* GetStr() const
{
return(m_pBuff);
}
//拼接追加
CMyString& Append(const char* sz);
CMyString& Append(const CMyString& sz);
CMyString& Append(char ch);
CMyString& Append(int n);
CMyString& Append(float f);
CMyString& Append(double dbl);
//查询
int Find(const char* sz); //-1 找不到
int Find(const CMyString& obj);
int ReverseFind(const char* sz);
int ReverseFind(const CMyString& obj);
//拷贝
CMyString& Copy(const char* sz);
CMyString& Copy(const CMyString& obj);
//比较
int Compare(const char* sz);
int Compare(const CMyString& obj);
//字串提取
CMyString Left(size_t nCount); //从字符串左侧提出nCount个字符
CMyString Right(size_t nCount);
CMyString Mid(int nIdx, size_t nCount);//从索引nIdx提出nCount个字符
static CMyString ValueOf(bool);
static CMyString ValueOf(char c);
static CMyString ValueOf(double d);
static CMyString ValueOf(float f);
static CMyString ValueOf(int i);
static CMyString ValueOf(long i);
static CMyString ValueOf(short i);
static CMyString ValueOf(const char* data);
static CMyString CopyValueOf(const char* data, int offset, int count);
static CMyString StringFromFormat(const char *format, ...);
private:
bool Init(char* pBuff, size_t size_t_Len, size_t size_t_BufSize, size_t* pSize_t_Cnt);
void SetStr(const char* sz);
void ZeroMemory(CMyString *pCStr);
void DeleteMemory();
void ReverseString(char *pszStr);
private:
char* m_pBuff = nullptr; // 存储字符串的缓冲区
size_t m_nLen; // 字符串的长度
size_t m_nBuffSize; // 缓冲区的大小
size_t *m_pSize_t_Cnt; // 引用计数
};
#endif
接着是cpp文件
#define _CRT_SECURE_NO_WARNINGS
#include "CMyString.h"
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cstdarg>
CMyString::CMyString()
{
ZeroMemory(this);
}
CMyString::CMyString(
const char* sz
)
{
int iLen = 0;
if (nullptr != sz)
{
iLen = strlen(sz) + 1;
Init((char *)sz, iLen - 1, iLen, nullptr);
}
else
{
ZeroMemory(this);
}
}
CMyString::CMyString(
const CMyString& obj
)
{
Init(obj.m_pBuff, obj.m_nLen, obj.m_nBuffSize, obj.m_pSize_t_Cnt);
}
CMyString::CMyString(
char ch
)
{
if ((ch >= 32) && (ch <= 126))
{
char szBuf[2] = { 0 };
szBuf[0] = ch;
Init(szBuf, 1, 2, nullptr);
}
else
{
ZeroMemory(this);
}
}
CMyString::~CMyString()
{
DeleteMemory();
}
void
CMyString::DeleteMemory()
{
int iCnt = 0;
if (nullptr != m_pBuff)
{
--(*m_pSize_t_Cnt);
iCnt = *m_pSize_t_Cnt;
if (0 >= iCnt)
{
delete[] m_pBuff;
delete m_pSize_t_Cnt;
ZeroMemory(this);
}
}
}
void
CMyString::ReverseString(
char* pszStr
)
{
size_t uiLenOfString = 0;
char ch;
if (nullptr == pszStr)
{
return;
}
uiLenOfString = strlen(pszStr);
for (size_t i = 0, j = uiLenOfString - 1; i < j; ++i, --j)
{
ch = pszStr[i];
pszStr[i] = pszStr[j];
pszStr[j] = ch;
}
}
CMyString&
CMyString::Append(
const char* sz
)
{
size_t iLen = 0;
size_t iTotalLen = 0;
char* pNewBuf = nullptr;
if (nullptr == sz)
{
return(*this);
}
iLen = strlen(sz);
if (nullptr != m_pBuff)
{
// 获取加上新字符串需要的总长
iTotalLen = iLen + m_nLen + 1;
// 如果原堆内存空间足够容纳新增字符串, 直接strcat
if (m_nBuffSize >= iTotalLen)
{
strcat(m_pBuff, sz);
}
// 不满足的情况, 需要重新分配内存
else
{
// 分配新内存
pNewBuf = new char[iTotalLen];
// 分配成功
if (nullptr != pNewBuf)
{
// 把新旧内容拷贝进来
memset(pNewBuf, 0, iTotalLen);
strcpy(pNewBuf, m_pBuff);
strcat(pNewBuf, sz);
// 删掉原内存并指向新的字符串
delete[] m_pBuff;
m_pBuff = pNewBuf;
m_nBuffSize = iTotalLen;
m_nLen = iTotalLen - 1;
}
// 分配内存没成功, 什么也不用做
else
{
}
}
}
else
{
// m_pBuff为nullptr初始化调用了默认构造
Init((char*)sz, iLen, iLen + 1, nullptr);
}
return(*this);
}
CMyString&
CMyString::Append(
const CMyString& sz
)
{
return(Append(sz.GetStr()));
}
CMyString&
CMyString::Append(
char ch
)
{
char szBuf[2] = { 0 };
szBuf[0] = ch;
return(Append(szBuf));
}
CMyString&
CMyString::Append(
int n
)
{
char szNumBuf[128] = { 0 };
sprintf(szNumBuf, "%d", n);
return(Append(szNumBuf));
}
CMyString&
CMyString::Append(
float f
)
{
char szNumBuf[128] = { 0 };
sprintf(szNumBuf, "%f", f);
return(Append(szNumBuf));
}
CMyString&
CMyString::Append(
double dbl
)
{
char szNumBuf[128] = { 0 };
sprintf(szNumBuf, "%lf", dbl);
return(Append(szNumBuf));
}
// 这里使用了朴素字符串匹配算法
int
CMyString::Find(
const char* sz
)
{
size_t uiLenOfDst = 0;
size_t uiLenOfMod = 0;
size_t uiCurPosOfDst = uiLenOfDst;
size_t uiTotalLenOfMod = 0;
size_t uiTotalLenOfDst = 0;
if ((nullptr == sz) || (nullptr == m_pBuff))
{
return(-1);
}
uiTotalLenOfMod = strlen(sz);
uiTotalLenOfDst = strlen(m_pBuff);
do
{
if (uiTotalLenOfDst <= uiLenOfDst)
{
return(-1);
}
if (sz[uiLenOfMod] == m_pBuff[uiLenOfDst])
{
++uiLenOfDst;
++uiLenOfMod;
if (uiTotalLenOfMod <= uiLenOfMod)
{
return(uiLenOfDst - uiTotalLenOfMod);
}
}
else
{
++uiCurPosOfDst;
uiLenOfDst = uiCurPosOfDst;
uiLenOfMod = 0;
}
} while (true);
}
int
CMyString::Find(
const CMyString& obj
)
{
return(Find(obj.m_pBuff));
}
int
CMyString::ReverseFind(
const char* sz
)
{
size_t uiLenOfsz = 0;
int iPos = 0;
char* pNewBuf = nullptr;
uiLenOfsz = strlen(sz);
pNewBuf = new char[uiLenOfsz + 1];
memset(pNewBuf, 0, uiLenOfsz + 1);
strcpy(pNewBuf, sz);
ReverseString(pNewBuf);
ReverseString(m_pBuff);
iPos = Find(pNewBuf);
ReverseString(m_pBuff);
if (-1 == iPos)
{
return(iPos);
}
return(m_nLen - iPos - uiLenOfsz);
}
int
CMyString::ReverseFind(
const CMyString& obj
)
{
return(ReverseFind(obj.m_pBuff));
}
CMyString&
CMyString::Copy(
const char* sz
)
{
size_t uiLen = 0;
if (nullptr == sz)
{
exit(1);
}
uiLen = strlen(sz);
// 如果对象的字符缓冲区是nullptr需要重新分配
if (nullptr == m_pBuff)
{
Init(m_pBuff, uiLen, uiLen + 1, nullptr);
}
else
{
delete[] m_pBuff;
m_pBuff = new char[uiLen + 1];
memset(m_pBuff, 0, uiLen + 1);
strcpy(m_pBuff, sz);
m_nLen = uiLen;
m_nBuffSize = uiLen + 1;
}
return(*this);
}
CMyString&
CMyString::Copy(
const CMyString& obj
)
{
Copy(obj.m_pBuff);
return(*this);
}
int
CMyString::Compare(
const char* sz
)
{
size_t uiNumOfStr = 0;
size_t uiIndex = 0;
if (nullptr == sz)
{
exit(1);
}
uiNumOfStr = strlen(sz);
if (m_nLen != uiNumOfStr)
{
return(m_nLen - uiNumOfStr);
}
for (uiIndex = 0; uiIndex < uiNumOfStr; ++uiIndex)
{
if (m_pBuff[uiIndex] != sz[uiIndex])
{
return(m_pBuff[uiIndex] - sz[uiIndex]);
}
}
return(0);
}
int
CMyString::Compare(
const CMyString& obj
)
{
return(Compare(obj.m_pBuff));
}
CMyString
CMyString::Left(
size_t nCount
)
{
CMyString CStr;
char* pNewBuf = nullptr;
// 如果当前对象没内容则直接返回空的对象
if (nullptr == m_pBuff || (m_nLen <= 0))
{
return(CStr);
}
// 如果当前对象字符总字数小于要求的字符数量,则直接浅拷贝
if ((m_nLen > 0) && (m_nLen <= nCount))
{
CStr.Init(m_pBuff, m_nLen, m_nBuffSize, m_pSize_t_Cnt);
return(CStr);
}
else
{
pNewBuf = new char[nCount + 1];
memset(pNewBuf, 0, nCount + 1);
strncpy(pNewBuf, m_pBuff, nCount);
CStr.Init(pNewBuf, nCount, nCount + 1, nullptr);
return(CStr);
}
}
CMyString
CMyString::Right(
size_t nCount
)
{
CMyString CStr;
char* pNewBuf = nullptr;
// 如果当前对象没内容则直接返回空的对象
if (nullptr == m_pBuff || (m_nLen <= 0))
{
return(CStr);
}
// 如果当前对象字符总字数小于要求的字符数量,则直接浅拷贝
if ((m_nLen > 0) && (m_nLen <= nCount))
{
CStr.Init(m_pBuff, m_nLen, m_nBuffSize, m_pSize_t_Cnt);
return(CStr);
}
else
{
pNewBuf = new char[nCount + 1];
memset(pNewBuf, 0, nCount + 1);
size_t uiLen = strlen(m_pBuff);
memcpy(pNewBuf, m_pBuff + uiLen - nCount, nCount);
CStr.Init(pNewBuf, nCount, nCount + 1, nullptr);
return(CStr);
}
}
CMyString
CMyString::Mid(
int nIdx,
size_t nCount
)
{
char* pBuf = nullptr;
if (nIdx + nCount > m_nLen)
{
return(CMyString());
}
pBuf = new char[nCount + 1];
if (nullptr == pBuf)
{
return(CMyString());
}
memset(pBuf, 0, nCount + 1);
memcpy(pBuf, m_pBuff + nIdx, nCount);
CMyString strRet(pBuf);
delete[] pBuf;
return(strRet);
//CMyString CStr;
//char* pNewBuf = nullptr;
如果当前对象没内容则直接返回空的对象
//if (nullptr == m_pBuff || (m_nLen <= 0))
//{
// return(CStr);
//}
判定参数是否符合规定
//if ((nIdx >= m_nLen) || (m_nLen < (nIdx + nCount)))
//{
// return(CStr);
//}
//CStr.Init(m_pBuff + nIdx, nCount, nCount + 1, nullptr);
//return(CStr);
}
CMyString
CMyString::ValueOf(
bool fBoolean
)
{
CMyString CStr;
char szTrueBuf[] = "true";
char szFalseBuf[] = "false";
CStr.Init(
(fBoolean ? szTrueBuf : szFalseBuf),
(fBoolean ? strlen(szTrueBuf) : strlen(szFalseBuf)),
(fBoolean ? (strlen(szTrueBuf) + 1) : (strlen(szFalseBuf) + 1)),
nullptr
);
return(CStr);
}
CMyString
CMyString::ValueOf(
char c
)
{
return(CMyString(c));
}
CMyString
CMyString::ValueOf(
double d
)
{
char szBuf[64] = { 0 };
size_t uiLen = 0;
CMyString CStr;
sprintf(szBuf, "%lf", d);
uiLen = strlen(szBuf);
CStr.Init(szBuf, uiLen, uiLen + 1, nullptr);
return(CStr);
}
CMyString
CMyString::ValueOf(
float f
)
{
char szBuf[64] = { 0 };
size_t uiLen = 0;
CMyString CStr;
sprintf(szBuf, "%f", f);
uiLen = strlen(szBuf);
CStr.Init(szBuf, uiLen, uiLen + 1, nullptr);
return(CStr);
}
CMyString
CMyString::ValueOf(
int i
)
{
char szBuf[64] = { 0 };
size_t uiLen = 0;
CMyString CStr;
sprintf(szBuf, "%d", i);
uiLen = strlen(szBuf);
CStr.Init(szBuf, uiLen, uiLen + 1, nullptr);
return(CStr);
}
CMyString
CMyString::ValueOf(
long i
)
{
char szBuf[64] = { 0 };
size_t uiLen = 0;
CMyString CStr;
sprintf(szBuf, "%ld", i);
uiLen = strlen(szBuf);
CStr.Init(szBuf, uiLen, uiLen + 1, nullptr);
return(CStr);
}
CMyString
CMyString::ValueOf(
short i
)
{
char szBuf[64] = { 0 };
size_t uiLen = 0;
CMyString CStr;
sprintf(szBuf, "%hd", i);
uiLen = strlen(szBuf);
CStr.Init(szBuf, uiLen, uiLen + 1, nullptr);
return(CStr);
}
CMyString
CMyString::ValueOf(
const char* data
)
{
CMyString CStr(data);
return(CStr);
}
CMyString
CMyString::CopyValueOf(
const char* data,
int offset,
int count
)
{
CMyString CStr(data);
return(CStr.Mid(offset, count));
}
CMyString
CMyString::StringFromFormat(
const char* format,
...
)
{
va_list vl;
va_start(vl, format);
int iSize = _vscprintf(format, vl) + 1;
char* pBuff = new char[iSize];
memset(pBuff, 0, iSize);
vsprintf(pBuff, format, vl);
va_end(vl);
CMyString strRet(pBuff);
// delete[]pBuff;
return(strRet);
}
bool
CMyString::Init(
char* pBuff,
size_t size_t_Len,
size_t size_t_BufSize,
size_t *pSize_t_Cnt
)
// 只有在指针未分配情况下才可以用此函数初始化
// 假设由于形参问题出了错,在构造情况下会直接调用默认构造,如果是拷贝情况形参是不大可能(除非人为)出错
// 因为拷贝构造必定是由另一个对象进行拷贝的, 那个对象的类成员必定符合要求
{
do
{
if (nullptr == pBuff)
{
break;
}
if (size_t_Len >= size_t_BufSize)
{
break;
}
m_nLen = size_t_Len;
m_nBuffSize = size_t_BufSize;
// 这里代表是构造进来的, 需要重新构造
if (nullptr == pSize_t_Cnt)
{
m_pBuff = new char[size_t_BufSize];
if (nullptr == m_pBuff)
{
break;
}
memset(m_pBuff, 0, size_t_BufSize);
strcpy(m_pBuff, pBuff);
m_pSize_t_Cnt = new size_t(1);
if (nullptr == m_pSize_t_Cnt)
{
delete[] m_pBuff;
m_pBuff = nullptr;
}
}
// 这里代表是拷贝构造进来的, 仅浅拷贝+提升引用计数
else
{
m_pBuff = pBuff;
m_pSize_t_Cnt = pSize_t_Cnt;
++(*m_pSize_t_Cnt);
}
} while (false);
if (nullptr == m_pBuff)
{
ZeroMemory(this);
return(false);
}
return(true);
}
void
CMyString::SetStr(
const char* sz
)
{
int iLen = 0;
if (nullptr == sz)
{
return;
}
iLen = strlen(sz);
if (nullptr == m_pBuff)
{
//
//
//
//
}
}
void
CMyString::ZeroMemory(
CMyString* pCStr
)
{
if (nullptr == pCStr)
{
return;
}
pCStr->m_nBuffSize = 0;
pCStr->m_nLen = 0;
pCStr->m_pBuff = nullptr;
pCStr->m_pSize_t_Cnt = nullptr;
}
最后是测试用的main函数:
#include <iostream>
#include <cstdlib>
#include "CMyString.h"
using namespace std;
int main()
{
CMyString CMyStr("Hello, world!");
int iNum = 128;
long lNum = 128;
short sNum = 128;
if (CMyStr.Compare("Hello, world!"))
{
cout << "不相等" << endl;
}
else
{
cout << "相等" << endl;
}
CMyStr.Copy("the word the the!");
cout << CMyStr.GetStr();
cout << CMyStr.Left(4).GetStr();
cout << CMyStr.Right(6).GetStr();
cout << CMyStr.Find("the");
cout << CMyStr.ReverseFind("the");
cout << CMyStr.GetStr() << endl;
cout << CMyString::ValueOf(false).GetStr() << endl;
cout << CMyString::ValueOf(4.15).GetStr() << endl;
cout << CMyString::ValueOf(5.162f).GetStr() << endl;
cout << CMyString::ValueOf(iNum).GetStr() << endl;
cout << CMyString::ValueOf(lNum).GetStr() << endl;
cout << CMyString::ValueOf(sNum).GetStr() << endl;
cout << CMyString::ValueOf("Back Off").GetStr() << endl;
cout << CMyStr.Mid(5, 3).GetStr() << endl;
CMyString str = CMyStr.CopyValueOf("Hello, world", 7, 5);
cout << str.GetStr();
cout << str.StringFromFormat("%s %s", "What", "the").GetStr();
str.Append("Fuck the world").Append(3.14).Append(555);
cout << str.GetStr();
system("pause");
return(0);
}
(完)