标题
自己的实用 string 类[持续多版本更新]
我是马甲
浏览(0) +
2007-12-05 17:45:43 发表
编辑
关键字:
自己的实用 string 类[持续多版本更新] 目的主要是 symbian 中不能用 stl ,而在 ppc 中含有 stl 的代码要移植过来. 每一版本都放上来,看看演化过程好了 :) 只是能用,效率可高不到哪去 :)
我是马甲
sstring.h -------------------------------------------------- #ifndef __SSTRING_H__ #define __SSTRING_H__ //自己的 sstring 类//self sstring 之意//主要用在不支持 std::string 的地方 #include #include class sstring { private: char * buf;//保存内容 int buf_len;//内容缓冲区长度//注意实际分配的内存区要大 1 个字节,因为 \0 的原因 public://基础的 sstring(); sstring(const char *s); sstring(const sstring &s); sstring& operator=(const char *); sstring& operator=(const sstring&); ~sstring(); char &operator[](int i); char operator[](int i) const; bool operator==(const sstring &) const; bool operator!=(const sstring &) const; sstring operator+(const sstring &) const; int length() const; operator char*(); //clq ? 不知道用来干嘛 // friend std::ostream &operator<<(std::ostream&, const sstring&); // friend std::istream &operator>>(std::istream&, sstring &); sstring & sstring::operator +=(const char *str); sstring & sstring::operator +=(const sstring &str); public://stl 兼容的 int size(); int compare(const sstring &str); const char * c_str(); //开始复制的索引,复制的字符个数 //sstring substr(int index = 0, int count = -1) const;//奇怪这个声明过不去 sstring sstring::substr(int index = 0, int count = -1); //查找一个字符 int find(const char c); void clear(); bool empty(); //在某个位置插入字符串 sstring & insert(int index, const sstring adds); sstring & sstring::operator +=(const char c); sstring(const char *s, int len); sstring(const char c); public://扩展的 bool eq(const sstring &str);//是否相等 int cmp(const sstring &str);//是否相等 }; //typedef sstring string;//没有 std::string 的地方可以再这样定义 #endif -------------------------------------------------- sstring.cpp -------------------------------------------------- //自己的 string 类//self string 之意//主要用在不支持 std::string 的地方 #include #include #include #include "sstring.h" sstring::sstring() { buf_len = 0; buf = (char *)malloc(buf_len+1); memset(buf, 0, buf_len+1); } //这个是干嘛的,实在不明白 sstring::operator char *() { return buf; } sstring::sstring(const char *s) { buf_len=strlen(s); buf = (char *)malloc(buf_len+1); strcpy(buf,s); } sstring::sstring(const char *s, int len) { buf_len = len; buf = (char *)malloc(buf_len+1); memset(buf, 0, buf_len+1); memcpy(buf, s, len); } sstring::sstring(const char c) { buf_len = 1; buf = (char *)malloc(buf_len+1); memset(buf, 0, buf_len+1); buf[0] = c; } sstring::sstring(const sstring &s) { buf_len = s.buf_len; buf = (char *)malloc(buf_len+1); memset(buf, 0, buf_len+1); //strcpy(buf,s.buf); memcpy(buf, s.buf, buf_len); } sstring& sstring::operator=(const char *c) { free(buf); buf_len=strlen(c); buf = (char *)malloc(buf_len+1); strcpy(buf,c); return *this; } sstring& sstring::operator=(const sstring &c) { if(this==&c) return *this; free(buf); buf_len = c.buf_len; buf = (char *)malloc(buf_len+1); strcpy(buf,c.buf); return *this; } sstring::~sstring() { free(buf); buf = NULL; buf_len = 0; } char& sstring::operator[](int i) { return buf[i]; } char sstring::operator[](int i) const { return buf[i]; } bool sstring::operator==(const sstring &c) const { //直接比较缓冲区的指针?似乎没有必要 //return(buf==c.buf); //从 vs2005 的源码看来应该是比较二者的内容 if (buf_len != c.buf_len) return false; int r = memcmp(buf, c.buf, c.buf_len); if (r == 0) return true; else return false; } bool sstring::operator!=(const sstring &c) const { //bool r = if ((*this) == c) return false; else return true; } sstring sstring::operator+(const sstring &c) const {//这个函数的实现有问题,以后要用 memcpy 改写, 因为 strcat 这样的函数太危险了 //这个和 += 操作符实现的区别应该是不改变自身 int buf_len1 = c.buf_len; int buf_len0 = buf_len1+buf_len; char *buf0 = (char *)malloc(buf_len0 + 1); memset(buf0, 0, buf_len0); strcpy(buf0, buf); strcat(buf0, c.buf); sstring sum(buf0); return sum; } sstring & sstring::operator+=(const char *str) { /* sstring temp(*this); buf_len += strlen (str); _string = new char[_size + 1]; strcpy (_string, temp.c_str ()); strcpy (_string+temp.size (), str); return *this; */ //关键点是返回值和自身的值都要加上字符串,所以一般是返回自己本身,也就是 (*this) sstring s = (*this); s = s + str; (*this) = s;//不可少 return s; } sstring & sstring::operator+=(const char c) { sstring str = c; sstring s = (*this); s = s + str; (*this) = s;//不可少 return s; } //在某个位置加入字符串 sstring & sstring::insert(int index, const sstring adds) { sstring s = (*this); sstring left = s.substr(0, index); sstring right = s.substr(index, -1); s = left + adds + right; (*this) = s;//不可少 return s; } //开始复制的索引,复制的字符个数 sstring sstring::substr(int index, int count) { sstring s = ""; int b = index;//起始位置 int e = index + count;//结束位置 if (count == -1) e = buf_len; if (e > buf_len)//不能超过最后的字符 e = buf_len; int len = e - b; if (len < 1) return s; s.buf = (char *)malloc(len+1); s.buf_len = len; memset(s.buf, 0, len+1); memcpy(s.buf, this->buf + index, len); return s; } //查找一个字符 int sstring::find(const char c) { int r = -1;//结果为 -1 就是没找到 for (int i=0; ibuf_len; i++) { if (this->buf[i] == c) { r = i; break; } } return r; } sstring & sstring::operator+=(const sstring &str) { /* String temp(*this); _size += str.size (); _string = new char[_size + 1]; strcpy (_string, temp.c_str ()); //strcat (_string , str.c_str ()); strcpy (_string+temp.size (), str.c_str ()); return *this; */ //关键点是返回值和自身的值都要加上字符串,所以一般是返回自己本身,也就是 (*this) sstring s = (*this); s = s + str; (*this) = s;//不可少 return s; } int sstring::length() const { return buf_len; } /* std::ibufeam&operator>>(std::ibufeam&in, sstring &x) { //in>>x.buf_len>>x.buf; } std::obufeam &operator<<(std::obufeam&out, const sstring&x) { //out< } */ int sstring::size() { return buf_len; } bool sstring::eq(const sstring &str)//是否相等 { int r = strcmp((*this).buf, str.buf); return r == 0; } int sstring::cmp(const sstring &str)//是否相等 { int r = strcmp((*this).buf, str.buf); return r; } int sstring::compare(const sstring &str)//是否相等 { return cmp(str); } const char * sstring::c_str() { return buf; } void sstring::clear() { delete [] buf; buf = NULL; buf_len = 0; } bool sstring::empty() { return (buf_len == 0); }
我是马甲
2007-12-19 21:43:06 发表
编辑
好了,这是一个经过 symbian 系统考验的版本.在用可变参数时老崩溃,我上看下看都不知道错在哪里,简直要怀疑自己写的字符串类太烂.结果是 symbian 的可变参数在处理整数时有问题,例如 //void CPacketParser::InitRequest(unsigned int nSequence, unsigned short nFuncNo, ...);//clq 这个在真机上会崩溃 void CPacketParser::InitRequest(const char * nSequence, const char * nFuncNo, ...);//clq modify //全部用字符串才行 -------------------------------------------------- 好了,代码如下. -------------------------------------------------- #ifndef __SSTRING_H__ #define __SSTRING_H__ //自己的 sstring 类//self sstring 之意//主要用在不支持 std::string 的地方 #include #include class sstring { private: char * buf;//保存内容 int buf_len;//内容缓冲区长度//注意实际分配的内存区要大 1 个字节,因为 \0 的原因 public://基础的 sstring(); sstring(const char *s); sstring(const sstring &s); sstring& operator=(const char *); sstring& operator=(const sstring&); ~sstring(); char &operator[](int i); char operator[](int i) const; bool operator==(const sstring &) const; bool operator!=(const sstring &) const; sstring operator+(const sstring &) const; int length() const; operator char*(); //clq ? 不知道用来干嘛 // friend std::ostream &operator<<(std::ostream&, const sstring&); // friend std::istream &operator>>(std::istream&, sstring &); sstring & sstring::operator +=(const char *str); sstring & sstring::operator +=(const sstring &str); public://stl 兼容的 int size(); int compare(const sstring &str); const char * c_str(); //开始复制的索引,复制的字符个数 //sstring substr(int index = 0, int count = -1) const;//奇怪这个声明过不去 sstring sstring::substr(int index = 0, int count = -1); //查找一个字符 int find(const char c); void clear(); bool empty(); //在某个位置插入字符串 sstring & insert(int index, const sstring adds); sstring & sstring::operator +=(const char c); sstring(const char *s, int len); sstring(const char c); public://扩展的 bool eq(const sstring &str);//是否相等 int cmp(const sstring &str);//是否相等 }; //typedef sstring string;//没有 std::string 的地方可以再这样定义 #endif -------------------------------------------------- 上面为 .h ,下面为 .cpp -------------------------------------------------- //自己的 string 类//self string 之意//主要用在不支持 std::string 的地方 #include #include #include #include "sstring.h" sstring::sstring() { buf_len = 0; buf = (char *)malloc(buf_len+1); //buf = (char *)malloc(1); memset(buf, 0, buf_len+1); } //这个是干嘛的,实在不明白 sstring::operator char *() { return buf; } sstring::sstring(const char *s) { buf_len=strlen(s); buf = (char *)malloc(buf_len+1); strcpy(buf,s); } sstring::sstring(const char *s, int len) { buf_len = len; buf = (char *)malloc(buf_len+1); memset(buf, 0, buf_len+1); memcpy(buf, s, len); } sstring::sstring(const char c) { buf_len = 1; buf = (char *)malloc(buf_len+1); memset(buf, 0, buf_len+1); buf[0] = c; } sstring::sstring(const sstring &s) { buf_len = s.buf_len; buf = (char *)malloc(buf_len+1); memset(buf, 0, buf_len+1); //strcpy(buf,s.buf); memcpy(buf, s.buf, buf_len); } sstring& sstring::operator=(const char *c) { free(buf); buf_len=strlen(c); buf = (char *)malloc(buf_len+1); memset(buf, 0, buf_len+1); if (buf_len > 0) { //strcpy(buf,c); memcpy(buf, c, buf_len); } return *this; } sstring& sstring::operator=(const sstring &c) { if(this==&c) return *this; free(buf); buf_len = c.buf_len; buf = (char *)malloc(buf_len+1); memset(buf, 0, buf_len+1); //strcpy(buf,c.buf); memcpy(buf, c.buf, c.buf_len); return *this; } sstring::~sstring() { free(buf); buf = NULL; buf_len = 0; } char& sstring::operator[](int i) { return buf[i]; } char sstring::operator[](int i) const { return buf[i]; } bool sstring::operator==(const sstring &c) const { //直接比较缓冲区的指针?似乎没有必要 //return(buf==c.buf); //从 vs2005 的源码看来应该是比较二者的内容 if (buf_len != c.buf_len) return false; int r = memcmp(buf, c.buf, c.buf_len); if (r == 0) return true; else return false; } bool sstring::operator!=(const sstring &c) const { //bool r = if ((*this) == c) return false; else return true; } sstring sstring::operator+(const sstring &c) const {//这个函数的实现有问题,以后要用 memcpy 改写, 因为 strcat 这样的函数太危险了 //这个和 += 操作符实现的区别应该是不改变自身 int buf_len1 = c.buf_len; int buf_len0 = buf_len1+buf_len; char *buf0 = (char *)malloc(buf_len0 + 1); memset(buf0, 0, buf_len0 + 1); strcpy(buf0, buf); strcat(buf0, c.buf); sstring sum(buf0); return sum; } sstring & sstring::operator+=(const char *str) { /* sstring temp(*this); buf_len += strlen (str); _string = new char[_size + 1]; strcpy (_string, temp.c_str ()); strcpy (_string+temp.size (), str); return *this; */ //关键点是返回值和自身的值都要加上字符串,所以一般是返回自己本身,也就是 (*this) sstring s = (*this); s = s + str; (*this) = s;//不可少 return s; return s; } sstring & sstring::operator+=(const char c) { sstring str = c; sstring s = (*this); s = s + str; (*this) = s;//不可少 return s; } //在某个位置加入字符串 sstring & sstring::insert(int index, const sstring adds) { sstring s = (*this); sstring left = s.substr(0, index); sstring right = s.substr(index, -1); s = left + adds + right; (*this) = s;//不可少 return s; } //开始复制的索引,复制的字符个数 sstring sstring::substr(int index, int count) { sstring s = ""; int b = index;//起始位置 int e = index + count;//结束位置 if (count == -1) e = buf_len; if (e > buf_len)//不能超过最后的字符 e = buf_len; int len = e - b; if (len < 1) return s; free(s.buf); s.buf = NULL; s.buf = (char *)malloc(len+1); s.buf_len = len; memset(s.buf, 0, len+1); memcpy(s.buf, this->buf + index, len); return s; } //查找一个字符 int sstring::find(const char c) { int r = -1;//结果为 -1 就是没找到 for (int i=0; ibuf_len; i++) { if (this->buf[i] == c) { r = i; break; } } return r; } sstring & sstring::operator+=(const sstring &str) { /* String temp(*this); _size += str.size (); _string = new char[_size + 1]; strcpy (_string, temp.c_str ()); //strcat (_string , str.c_str ()); strcpy (_string+temp.size (), str.c_str ()); return *this; */ //关键点是返回值和自身的值都要加上字符串,所以一般是返回自己本身,也就是 (*this) sstring s = (*this); s = s + str; (*this) = s;//不可少 return s; } int sstring::length() const { return buf_len; } /* std::ibufeam&operator>>(std::ibufeam&in, sstring &x) { //in>>x.buf_len>>x.buf; } std::obufeam &operator<<(std::obufeam&out, const sstring&x) { //out< } */ int sstring::size() { return buf_len; } bool sstring::eq(const sstring &str)//是否相等 { int r = strcmp((*this).buf, str.buf); return r == 0; } int sstring::cmp(const sstring &str)//是否相等 { int r = strcmp((*this).buf, str.buf); return r; } int sstring::compare(const sstring &str)//是否相等 { return cmp(str); } const char * sstring::c_str() { return buf; } void sstring::clear() { free(buf); buf = NULL; buf_len = 0; buf_len = 0; buf = (char *)malloc(buf_len+1); memset(buf, 0, buf_len+1); } bool sstring::empty() { return (buf_len == 0); }
clq
2007-12-27 13:26:35 发表
编辑
sstring::operator char *() 原来是干这个的. 用于类型的转换,在 s60 [symbian] 模拟器上这个转换还是成功的,但真机上就不行,一定要手工写上 c_str() 以下是将各个参数当做 char * 处理的可变参数例子. -------------------------------------------------- //真机上有问题//好象是没调用 sstring::operator char *() 而直接转换了指针值 //parser.AppendRecord(iAppUi.iTradeListContainer->m_Direction, "10", iAppUi.iTradeListContainer->m_PositionStr.c_str(), "", 0); parser.AppendRecord((char *)iAppUi.iTradeListContainer->m_Direction.c_str(), "10", (char *)iAppUi.iTradeListContainer->m_PositionStr.c_str(), "", 0); -------------------------------------------------- 函数实现为: void CPacketParser::AppendRecord(char *param, ...) { char *pData = param; va_list arg_ptr; va_start(arg_ptr, param); while (pData) { m_Data += pData; m_Data += SEP; pData = va_arg(arg_ptr, char*); } m_iRows++; };
clq
2007-12-27 14:27:33 发表
编辑
根据 Effective C++ 的说明似乎不定义这个函数为好. -------------------------------------------------- 条款五:谨慎定义类型转换函数 C++编译器能够在两种数据类型之间进行隐式转换(implicit conversions),它继承了C语言的转换方法,例如允许把char隐式转换为int和从short隐式转换为double。因此当你把一个short值传递给准备接受double参数值的函数时,依然可以成功运行。C中许多这种可怕的转换可能会导致数据的丢失,它们在C++中依然存在,包括int到short的转换和double到char的转换。 你对这些类型转换是无能为力的,因为它们是语言本身的特性。不过当你增加自己的类型时,你就可以有更多的控制力,因为你能选择是否提供函数让编译器进行隐式类型转换。 有两种函数允许编译器进行这些的转换:单参数构造函数(single-argument constructors)和隐式类型转换运算符。单参数构造函数是指只用一个参数即可以调用的构造函数。该函数可以是只定义了一个参数,也可以是虽定义了多个参数但第一个参数以后的所有参数都有缺省值。以下有两个例子: class Name { // for names of things public: Name(const string& s); // 转换 string // Name ... }; class Rational { // 有理数类 public: Rational(int numerator = 0, // 转换int到 int denominator = 1); // 有理数类 ... }; 隐式类型转换运算符只是一个样子奇怪的成员函数:operator 关键字,其后跟一个类型符号。你不用定义函数的返回类型,因为返回类型就是这个函数的名字。例如为了允许Rational(有理数)类隐式地转换为double类型(在用有理数进行混合类型运算时,可能有用),你可以如此声明Rational类: class Rational { public: ... operator double() const; // 转换Rational类成 }; // double类型 在下面这种情况下,这个函数会被自动调用: Rational r(1, 2); // r 的值是1/2 double d = 0.5 * r; // 转换 r 到double, // 然后做乘法 以上这些说明只是一个复习,我真正想说的是为什么你不需要定义各中类型转换函数。 根本问题是当你在不需要使用转换函数时,这些的函数缺却能被调用运行。结果这些不正确的程序会做出一些令人恼火的事情,而你又很难判断出原因。 让我们首先分析一下隐式类型转换运算符,它们是最容易处理的。假设你有一个如上所述的Rational类,你想让该类拥有打印有理数对象的功能,就好像它是一个内置类型。因此,你可能会这么写: Rational r(1, 2); cout << r; // 应该打印出"1/2" 再假设你忘了为Rational对象定义operator<<。你可能想打印操作将失败,因为没有合适的的operator<<被调用。但是你错了。当编译器调用operator<<时,会发现没有这样的函数存在,但是它会试图找到一个合适的隐式类型转换顺序以使得函数调用正常运行。类型转换顺序的规则定义是复杂的,但是在这种情况下编译器会发现它们能调用Rational::operator double函数,来把r转换为double类型。所以上述代码打印的结果是一个浮点数,而不是一个有理数。这简直是一个灾难,但是它表明了隐式类型转换的缺点:它们的存在将导致错误的发生。 解决方法是用等同的函数来替代转换运算符,而不用语法关键字。例如为了把Rational对象转换为double,用asDouble函数代替operator double函数: class Rational { public: ... double asDouble() const; //转变 Rational }; // 成double 这个成员函数能被显式调用: Rational r(1, 2); cout << r; // 错误! Rationa对象没有 // operator<< cout << r.asDouble(); // 正确, 用double类型 //打印r 在多数情况下,这种显式转换函数的使用虽然不方便,但是函数被悄悄调用的情况不再会发生,这点损失是值得的。一般来说,越有经验的C++程序员就越喜欢避开类型转换运算符。例如在C++标准库(参见条款49和35)委员会工作的人员是在此领域最有经验的,他们加在库函数中的string类型没有包括隐式地从string转换成C风格的char*的功能,而是定义了一个成员函数c_str用来完成这个转换,这是巧合么?我看不是。 通过单参数构造函数进行隐式类型转换更难消除。而且在很多情况下这些函数所导致的问题要甚于隐式类型转换运算符。 举一个例子,一个array类模板,这些数组需要调用者确定边界的上限与下限: template class Array { public: Array(int lowBound, int highBound); Array(int size); T& operator[](int index); ... }; 第一个构造函数允许调用者确定数组索引的范围,例如从10到20。它是一个两参数构造函数,所以不能做为类型转换函数。第二个构造函数让调用者仅仅定义数组元素的个数(使用方法与内置数组的使用相似),不过不同的是它能做为类型转换函数使用,能导致无穷的痛苦。 例如比较Array对象,部分代码如下: bool operator==( const Array& lhs, const Array& rhs); Array a(10); Array b(10); ... for (int i = 0; i < 10; ++i) if (a == b[i]) { // 哎呦! "a" 应该是 "a[i]" do something for when a[i] and b[i] are equal; } else { do something for when they're not; } 我们想用a的每个元素与b的每个元素相比较,但是当录入a时,我们偶然忘记了数组下标。当然我们希望编译器能报出各种各样的警告信息,但是它根本没有。因为它把这个调用看成用Array参数(对于a)和int (对于b[i])参数调用operator==函数 ,然而没有operator==函数是这些的参数类型,我们的编译器注意到它能通过调用Array构造函数能转换int类型到Array类型,这个构造函数只有一个int 类型的参数。然后编译器如此去编译,生成的代码就象这样: for (int i = 0; i < 10; ++i) if (a == static_cast< Array >(b[i])) ... 每一次循环都把a的内容与一个大小为b[i]的临时数组(内容是未定义的)比较 。这不仅不可能以正确的方法运行,而且还是效率低下的。因为每一次循环我们都必须建立和释放Array对象(见条款19)。 通过不声明运算符(operator)的方法,可以克服隐式类型转换运算符的缺点,但是单参数构造函数没有那么简单。毕竟,你确实想给调用者提供一个单参数构造函数。同时你也希望防止编译器不加鉴别地调用这个构造函数。幸运的是,有一个方法可以让你鱼肉与熊掌兼得。事实上是两个方法:一是容易的方法,二是当你的编译器不支持容易的方法时所必须使用的方法。 容易的方法是利用一个最新编译器的特性,explicit关键字。为了解决隐式类型转换而特别引入的这个特性,它的使用方法很好理解。构造函数用explicit声明,如果这样做,编译器会拒绝为了隐式类型转换而调用构造函数。显式类型转换依然合法: template class Array { public: ... explicit Array(int size); // 注意使用"explicit" ... }; Array a(10); // 正确, explicit 构造函数 // 在建立对象时能正常使用 Array b(10); // 也正确 if (a == b[i]) ... // 错误! 没有办法 // 隐式转换 // int 到 Array if (a == Array(b[i])) ... // 正确,显式从int到 // Array转换 // (但是代码的逻辑 // 不合理) if (a == static_cast< Array >(b[i])) ... // 同样正确,同样 // 不合理 if (a == (Array)b[i]) ... //C风格的转换也正确, // 但是逻辑 // 依旧不合理 在例子里使用了static_cast(参见条款2),两个“>”字符间的空格不能漏掉,如果这样写语句: if (a == static_cast>(b[i])) ... 这是一个不同的含义的语句。因为C++编译器把”>>”做为一个符号来解释。在两个”>”间没有空格,语句会产生语法错误。 如果你的编译器不支持explicit,你不得不回到不使用成为隐式类型转换函数的单参数构造函数。(……) 我前面说过复杂的规则决定哪一个隐式类型转换是合法的,哪一个是不合法的。这些规则中没有一个转换能够包含用户自定义类型(调用单参数构造函数或隐式类型转换运算符)。你能利用这个规则来正确构造你的类,使得对象能够正常构造,同时去掉你不想要的隐式类型转换。 再来想一下数组模板,你需要用整形变量做为构造函数参数来确定数组大小,但是同时又必须防止从整数类型到临时数组对象的隐式类型转换。你要达到这个目的,先要建立一个新类ArraySize。这个对象只有一个目的就是表示将要建立数组的大小。你必须修改Array的单参数构造函数,用一个ArraySize对象来代替int。代码如下: template class Array { public: class ArraySize { // 这个类是新的 public: ArraySize(int numElements): theSize(numElements) {} int size() const { return theSize; } private: int theSize; }; Array(int lowBound, int highBound); Array(ArraySize size); // 注意新的声明 ... }; 这里把ArraySize嵌套入Array中,为了强调它总是与Array一起使用。你也必须声明ArraySize为公有,为了让任何人都能使用它。 想一下,当通过单参数构造函数定义Array对象,会发生什么样的事情: Array a(10); 你的编译器要求用int参数调用Array里的构造函数,但是没有这样的构造函数。编译器意识到它能从int参数转换成一个临时ArraySize对象,ArraySize对象只是Array构造函数所需要的,这样编译器进行了转换。函数调用(及其后的对象建立)也就成功了。 事实上你仍旧能够安心地构造Array对象,不过这样做能够使你避免类型转换。考虑一下以下代码: bool operator==( const Array& lhs, const Array& rhs); Array a(10); Array b(10); ... for (int i = 0; i < 10; ++i) if (a == b[i]) ... // 哎呦! "a" 应该是 "a[i]"; // 现在是一个错误。 为了调用operator==函数,编译器要求Array对象在”==”右侧,但是不存在一个参数为int的单参数构造函数。而且编译器无法把int转换成一个临时ArraySize对象然后通过这个临时对象建立必须的Array对象,因为这将调用两个用户定义(user-defined)的类型转换,一个从int到ArraySize,一个从ArraySize到Array。这种转换顺序被禁止的,所以当试图进行比较时编译器肯定会产生错误。 ArraySize类的使用有些象一个有目的的帮手,这是一个更通用技术的应用实例。类似于ArraySize的类经常被称为proxy classes,因为这样类的每一个对象都为了支持其他对象的工作。ArraySize对象实际是一个整数类型的替代者,用来在建立Array对象时确定数组大小。Proxy对象能帮你更好地控制软件的在某些方面的行为,否则你就不能控制这些行为,比如在上面的情况里,这种行为是指隐式类型转换,所以它值得你去学习和使用。你可能会问你如何去学习它呢?一种方法是转向条款33;它专门讨论proxy classes。 在你跳到条款33之前,再仔细考虑一下本条款的内容。让编译器进行隐式类型转换所造成的弊端要大于它所带来的好处,所以除非你确实需要,不要定义类型转换函数。
clq
在 bcb6 下,以上代码过不去.原因是 sstring & 返回值类型的函数不能返回临时变量.如下.所以对代码又做了些修改. sstring & sstring::operator+=(const sstring &str) { /* String temp(*this); _size += str.size (); _string = new char[_size + 1]; strcpy (_string, temp.c_str ()); //strcat (_string , str.c_str ()); strcpy (_string+temp.size (), str.c_str ()); return *this; */ //关键点是返回值和自身的值都要加上字符串,所以一般是返回自己本身,也就是 (*this) sstring s = (*this); s = s + str; (*this) = s;//不可少 //return s;//bcb6 下过不去 return *this; }
clq
#ifndef __SSTRING_H__ #define __SSTRING_H__ //自己的 sstring 类//self sstring 之意//主要用在不支持 std::string 的地方 #include #include class sstring { private: char * buf;//保存内容 int buf_len;//内容缓冲区长度//注意实际分配的内存区要大 1 个字节,因为 \0 的原因 public://基础的 sstring(); sstring(const char *s); sstring(const sstring &s); sstring& operator=(const char *); sstring& operator=(const sstring&); ~sstring(); char &operator[](int i); char operator[](int i) const; bool operator==(const sstring &) const; bool operator!=(const sstring &) const; sstring operator+(const sstring &) const; int length() const; operator char*(); //clq ? 不知道用来干嘛 // friend std::ostream &operator<<(std::ostream&, const sstring&); // friend std::istream &operator>>(std::istream&, sstring &); sstring & sstring::operator +=(const char *str); sstring & sstring::operator +=(const sstring &str); public://stl 兼容的 int size(); int compare(const sstring &str); const char * c_str(); char * data(); //开始复制的索引,复制的字符个数 //sstring substr(int index = 0, int count = -1) const;//奇怪这个声明过不去 sstring sstring::substr(int index = 0, int count = -1); //查找一个字符 int find(const char c); void clear(); bool empty(); //在某个位置插入字符串 sstring & insert(int index, const sstring adds); sstring & sstring::operator +=(const char c); sstring(const char *s, int len); sstring(const char c); public://扩展的 bool eq(const sstring &str);//是否相等 int cmp(const sstring &str);//是否相等 }; //typedef sstring string;//没有 std::string 的地方可以再这样定义 #endif -------------------------------------------------- //自己的 string 类//self string 之意//主要用在不支持 std::string 的地方 #include #include #include #include "sstring.h" sstring::sstring() { buf_len = 0; buf = (char *)malloc(buf_len+1); //buf = (char *)malloc(1); memset(buf, 0, buf_len+1); } //这个是干嘛的,实在不明白//是用在强制转换的吧 sstring::operator char *() { return buf; } sstring::sstring(const char *s) { buf_len=strlen(s); buf = (char *)malloc(buf_len+1); strcpy(buf,s); } sstring::sstring(const char *s, int len) { buf_len = len; buf = (char *)malloc(buf_len+1); memset(buf, 0, buf_len+1); memcpy(buf, s, len); } sstring::sstring(const char c) { buf_len = 1; buf = (char *)malloc(buf_len+1); memset(buf, 0, buf_len+1); buf[0] = c; } sstring::sstring(const sstring &s) { buf_len = s.buf_len; buf = (char *)malloc(buf_len+1); memset(buf, 0, buf_len+1); //strcpy(buf,s.buf); memcpy(buf, s.buf, buf_len); } sstring& sstring::operator=(const char *c) { free(buf); buf_len=strlen(c); buf = (char *)malloc(buf_len+1); memset(buf, 0, buf_len+1); if (buf_len > 0) { //strcpy(buf,c); memcpy(buf, c, buf_len); } return *this; } sstring& sstring::operator=(const sstring &c) { if(this==&c) return *this; free(buf); buf_len = c.buf_len; buf = (char *)malloc(buf_len+1); memset(buf, 0, buf_len+1); //strcpy(buf,c.buf); memcpy(buf, c.buf, c.buf_len); return *this; } sstring::~sstring() { free(buf); buf = NULL; buf_len = 0; } char& sstring::operator[](int i) { return buf[i]; } char sstring::operator[](int i) const { return buf[i]; } bool sstring::operator==(const sstring &c) const { //直接比较缓冲区的指针?似乎没有必要 //return(buf==c.buf); //从 vs2005 的源码看来应该是比较二者的内容 if (buf_len != c.buf_len) return false; int r = memcmp(buf, c.buf, c.buf_len); if (r == 0) return true; else return false; } bool sstring::operator!=(const sstring &c) const { //bool r = if ((*this) == c) return false; else return true; } sstring sstring::operator+(const sstring &c) const {//这个函数的实现有问题,以后要用 memcpy 改写, 因为 strcat 这样的函数太危险了 //这个和 += 操作符实现的区别应该是不改变自身 int buf_len1 = c.buf_len; int buf_len0 = buf_len1+buf_len; char *buf0 = (char *)malloc(buf_len0 + 1); memset(buf0, 0, buf_len0 + 1); strcpy(buf0, buf); strcat(buf0, c.buf); sstring sum(buf0); return sum; } sstring & sstring::operator+=(const char *str) { /* sstring temp(*this); buf_len += strlen (str); _string = new char[_size + 1]; strcpy (_string, temp.c_str ()); strcpy (_string+temp.size (), str); return *this; */ //关键点是返回值和自身的值都要加上字符串,所以一般是返回自己本身,也就是 (*this) sstring s = (*this); s = s + str; (*this) = s;//不可少 //return s;//bcb6 下过不去 return *this; } sstring & sstring::operator+=(const char c) { sstring str = c; sstring s = (*this); s = s + str; (*this) = s;//不可少 //return s;//bcb6 下过不去 return *this; } //在某个位置加入字符串 sstring & sstring::insert(int index, const sstring adds) { sstring s = (*this); sstring left = s.substr(0, index); sstring right = s.substr(index, -1); s = left + adds + right; (*this) = s;//不可少 //return s;//bcb6 下过不去 return *this; } //开始复制的索引,复制的字符个数 sstring sstring::substr(int index, int count) { sstring s = ""; int b = index;//起始位置 int e = index + count;//结束位置 if (count == -1) e = buf_len; if (e > buf_len)//不能超过最后的字符 e = buf_len; int len = e - b; if (len < 1) return s; free(s.buf); s.buf = NULL; s.buf = (char *)malloc(len+1); s.buf_len = len; memset(s.buf, 0, len+1); memcpy(s.buf, this->buf + index, len); return s; } //查找一个字符 int sstring::find(const char c) { int r = -1;//结果为 -1 就是没找到 for (int i=0; ibuf_len; i++) { if (this->buf[i] == c) { r = i; break; } } return r; } sstring & sstring::operator+=(const sstring &str) { /* String temp(*this); _size += str.size (); _string = new char[_size + 1]; strcpy (_string, temp.c_str ()); //strcat (_string , str.c_str ()); strcpy (_string+temp.size (), str.c_str ()); return *this; */ //关键点是返回值和自身的值都要加上字符串,所以一般是返回自己本身,也就是 (*this) sstring s = (*this); s = s + str; (*this) = s;//不可少 //return s;//bcb6 下过不去 return *this; } int sstring::length() const { return buf_len; } /* std::ibufeam&operator>>(std::ibufeam&in, sstring &x) { //in>>x.buf_len>>x.buf; } std::obufeam &operator<<(std::obufeam&out, const sstring&x) { //out< } */ int sstring::size() { return buf_len; } bool sstring::eq(const sstring &str)//是否相等 { int r = strcmp((*this).buf, str.buf); return r == 0; } int sstring::cmp(const sstring &str)//是否相等 { int r = strcmp((*this).buf, str.buf); return r; } int sstring::compare(const sstring &str)//是否相等 { return cmp(str); } const char * sstring::c_str() { return buf; } char * sstring::data() { return buf; } void sstring::clear() { free(buf); buf = NULL; buf_len = 0; buf_len = 0; buf = (char *)malloc(buf_len+1); memset(buf, 0, buf_len+1); } bool sstring::empty() { return (buf_len == 0); }
clq
bcb6 实现的 std::string 居然是有问题的!多个字符连接在一起后很容易内容就不对了.特别是里面有 char *, string , += 东西的时候.例如: std::string expires = "expires="+s_time+"; "; 这样一句简单的代码也会使其出错.
NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.