请问如何扩展stl库,如string

chenzhengxi001 2004-07-18 05:55:39
我在写一个软件主要是语法分析,所以很多都是处理字符串。
我必须自定义很多很多函数。用名字域包起来。
但是我想既然是用c++,那就干脆把string类扩展一下。
我看了一个下午的关如string的源文件,那简直不是人看的,居然含有很多语法形式我没见过的。
我简单的扩展了一下,其实就是继承string类吗,再添加我要实现的函数。
可事情没我想的美,错误多多,而且没法理解。
那位高手能给个实例。
我听台湾那个候作家说学习stl有3个境界,扩展stl是最高的。
...全文
584 点赞 收藏 42
写回复
42 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
shakaCY 2004-09-19
^_^,快搬个椅子来学习一下!
楼主是强人啊,解决问题了别忘通知一声啊!
回复
step_by_step 2004-09-14
不要做无谓的创新。

回复
caslwzgks 2004-09-14
对于STL组件来说,不应该叫做“继承”,而应该叫做扩展或实现定制组件更好一些。
要扩展STL就必须按照STL的规定提供一些类型定义、及方法,如下所示:
typedef basic_string<E> base;
typedef base::iterator iterator;
typedef base::const_iterator const_iterator;
typedef base::value_type value_type;
typedef base::size_type size_type;

我们还可采用private继承方式来实现 STL容器的子集:

template<class T>
class myVector : private std::vector< T >
{
public:
typedef std::vector<T> base;
typedef base::iterator iterator;
....
using base::size;
using base::begin;
using base::end;
using base::operator[];
using base::empty;
...//添加想要曝露的接口

};

这样myVector的客户只能使用myVector曝露的接口,而不能使用未曝露的vector方法。

回复
yjh1982 2004-09-14
用包含模式扩展就很简单么.
class newclass{
string imp;
};
又没虚函数,为什么一定要用继承呢?
回复
abcdf1983 2004-09-14
看这,我有点晕
回复
caslwzgks 2004-09-14
#ifndef STRINGEX_H
#define STRINGEX_H

template<class E>
class stringex : public basic_string<E>
{
public:
typedef basic_string<E> base;
typedef base::iterator iterator;
typedef base::const_iterator const_iterator;
typedef base::value_type value_type;
typedef base::size_type size_type;
typedef base::const_pointer const_pointer;

stringex(const E * rhs): base( rhs){}
stringex(E * rhs): base( rhs){}
stringex(const stringex<E> & rhs): base( rhs.c_str() ){}
stringex<E> & operator=( const stringex<E> & rhs)
{
base::operator=( rhs);
return *this;
}
stringex<E> & operator+( const stringex<E> & rhs)
{
base::operator+=(rhs.c_str() );
return *this;
}
};

#endif
回复
IDqq 2004-09-11
基本思想大概就是得到串的总长,分配空间,用的还是类似sprintf
回复
IDqq 2004-09-11
MFC的CString::Format

void CString::FormatV(LPCTSTR lpszFormat, va_list argList)
{
ASSERT(AfxIsValidString(lpszFormat));

va_list argListSave = argList;

// make a guess at the maximum length of the resulting string
int nMaxLen = 0;
for (LPCTSTR lpsz = lpszFormat; *lpsz != '\0'; lpsz = _tcsinc(lpsz))
{
// handle '%' character, but watch out for '%%'
if (*lpsz != '%' || *(lpsz = _tcsinc(lpsz)) == '%')
{
nMaxLen += _tclen(lpsz);
continue;
}

int nItemLen = 0;

// handle '%' character with format
int nWidth = 0;
for (; *lpsz != '\0'; lpsz = _tcsinc(lpsz))
{
// check for valid flags
if (*lpsz == '#')
nMaxLen += 2; // for '0x'
else if (*lpsz == '*')
nWidth = va_arg(argList, int);
else if (*lpsz == '-' || *lpsz == '+' || *lpsz == '0' ||
*lpsz == ' ')
;
else // hit non-flag character
break;
}
// get width and skip it
if (nWidth == 0)
{
// width indicated by
nWidth = _ttoi(lpsz);
for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
;
}
ASSERT(nWidth >= 0);

int nPrecision = 0;
if (*lpsz == '.')
{
// skip past '.' separator (width.precision)
lpsz = _tcsinc(lpsz);

// get precision and skip it
if (*lpsz == '*')
{
nPrecision = va_arg(argList, int);
lpsz = _tcsinc(lpsz);
}
else
{
nPrecision = _ttoi(lpsz);
for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
;
}
ASSERT(nPrecision >= 0);
}

// should be on type modifier or specifier
int nModifier = 0;
if (_tcsncmp(lpsz, _T("I64"), 3) == 0)
{
lpsz += 3;
nModifier = FORCE_INT64;
#if !defined(_X86_) && !defined(_ALPHA_)
// __int64 is only available on X86 and ALPHA platforms
ASSERT(FALSE);
#endif
}
else
{
switch (*lpsz)
{
// modifiers that affect size
case 'h':
nModifier = FORCE_ANSI;
lpsz = _tcsinc(lpsz);
break;
case 'l':
nModifier = FORCE_UNICODE;
lpsz = _tcsinc(lpsz);
break;

// modifiers that do not affect size
case 'F':
case 'N':
case 'L':
lpsz = _tcsinc(lpsz);
break;
}
}

// now should be on specifier
switch (*lpsz | nModifier)
{
// single characters
case 'c':
case 'C':
nItemLen = 2;
va_arg(argList, TCHAR_ARG);
break;
case 'c'|FORCE_ANSI:
case 'C'|FORCE_ANSI:
nItemLen = 2;
va_arg(argList, CHAR_ARG);
break;
case 'c'|FORCE_UNICODE:
case 'C'|FORCE_UNICODE:
nItemLen = 2;
va_arg(argList, WCHAR_ARG);
break;

// strings
case 's':
{
LPCTSTR pstrNextArg = va_arg(argList, LPCTSTR);
if (pstrNextArg == NULL)
nItemLen = 6; // "(null)"
else
{
nItemLen = lstrlen(pstrNextArg);
nItemLen = max(1, nItemLen);
}
}
break;

case 'S':
{
#ifndef _UNICODE
LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
if (pstrNextArg == NULL)
nItemLen = 6; // "(null)"
else
{
nItemLen = wcslen(pstrNextArg);
nItemLen = max(1, nItemLen);
}
#else
LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
if (pstrNextArg == NULL)
nItemLen = 6; // "(null)"
else
{
nItemLen = lstrlenA(pstrNextArg);
nItemLen = max(1, nItemLen);
}
#endif
}
break;

case 's'|FORCE_ANSI:
case 'S'|FORCE_ANSI:
{
LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
if (pstrNextArg == NULL)
nItemLen = 6; // "(null)"
else
{
nItemLen = lstrlenA(pstrNextArg);
nItemLen = max(1, nItemLen);
}
}
break;

case 's'|FORCE_UNICODE:
case 'S'|FORCE_UNICODE:
{
LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
if (pstrNextArg == NULL)
nItemLen = 6; // "(null)"
else
{
nItemLen = wcslen(pstrNextArg);
nItemLen = max(1, nItemLen);
}
}
break;
}

// adjust nItemLen for strings
if (nItemLen != 0)
{
if (nPrecision != 0)
nItemLen = min(nItemLen, nPrecision);
nItemLen = max(nItemLen, nWidth);
}
else
{
switch (*lpsz)
{
// integers
case 'd':
case 'i':
case 'u':
case 'x':
case 'X':
case 'o':
if (nModifier & FORCE_INT64)
va_arg(argList, __int64);
else
va_arg(argList, int);
nItemLen = 32;
nItemLen = max(nItemLen, nWidth+nPrecision);
break;

case 'e':
case 'g':
case 'G':
va_arg(argList, DOUBLE_ARG);
nItemLen = 128;
nItemLen = max(nItemLen, nWidth+nPrecision);
break;

case 'f':
{
double f;
LPTSTR pszTemp;

// 312 == strlen("-1+(309 zeroes).")
// 309 zeroes == max precision of a double
// 6 == adjustment in case precision is not specified,
// which means that the precision defaults to 6
pszTemp = (LPTSTR)_alloca(max(nWidth, 312+nPrecision+6));

f = va_arg(argList, double);
_stprintf( pszTemp, _T( "%*.*f" ), nWidth, nPrecision+6, f );
nItemLen = _tcslen(pszTemp);
}
break;

case 'p':
va_arg(argList, void*);
nItemLen = 32;
nItemLen = max(nItemLen, nWidth+nPrecision);
break;

// no output
case 'n':
va_arg(argList, int*);
break;

default:
ASSERT(FALSE); // unknown formatting option
}
}

// adjust nMaxLen for output nItemLen
nMaxLen += nItemLen;
}

GetBuffer(nMaxLen);
VERIFY(_vstprintf(m_pchData, lpszFormat, argListSave) <= GetAllocLength());
ReleaseBuffer();

va_end(argListSave);
}

// formatting (using wsprintf style formatting)
void AFX_CDECL CString::Format(LPCTSTR lpszFormat, ...)
{
ASSERT(AfxIsValidString(lpszFormat));

va_list argList;
va_start(argList, lpszFormat);
FormatV(lpszFormat, argList);
va_end(argList);
}

void AFX_CDECL CString::Format(UINT nFormatID, ...)
{
CString strFormat;
VERIFY(strFormat.LoadString(nFormatID) != 0);

va_list argList;
va_start(argList, nFormatID);
FormatV(strFormat, argList);
va_end(argList);
}
回复
IDqq 2004-09-11
扩充的话感觉用标准算法+迭代器还算比较简单吧,在高深一点恐怕就得读源码咯。
俺写的几个小方法,不改变源串Trim Left,Right,ToUpper,Tolower,Count char……
要是啥时候能实现CString的Format就更牛逼了。

感觉STL给的都是最基本的东西,靠近具体应用的话好多都得自己写。这点就和MFC不一样了。

inline string LTrim(string& str)
{
string::iterator pos=find_if(str.begin(),str.end(),not1(ptr_fun(isspace)));
return str.substr(distance(str.begin(),pos));
}

inline string RTrim(string& str)
{
string::reverse_iterator pos=find_if(str.rbegin(),str.rend(),not1(ptr_fun(isspace)));
return str.substr(0,distance(str.begin(),pos.base()));
}

inline string Trim(string& str)
{
return LTrim(RTrim(str));
}

inline string SubString(string& str, int start, int end)
{
assert(start>0 && end>0 && start<=end);
if (start > str.size()) {
return "";
}
--start;
return str.substr(start, end - start);
}

inline string ToUpper(string& str)
{
transform(str.begin(),str.end(),str.begin(),toupper);
return str;
}

inline string ToLower(string& str)
{
transform(str.begin(),str.end(),str.begin(),tolower);
return str;
}

inline int GetCharCount(string& str, char c)
{
return count(str.begin(),str.end(),c);
}
回复
bluejugar 2004-09-10
前一阵子也看了下STL的源文件,比如string.
真的不是人看了.

而且有好多好多不乱七八糟的语法.
MSDN里面检索也检索不到,好多还是递归定义的,看得我想砍人!!!

结果是越看越郁闷.
回复
cxn0808 2004-09-08
STL的扩展首先要选好合适的STL库,不同的库的代码组织不一样
像STLport,SGI STL,VC中的STL,它们的库的公用代码部分的组织形式稍有差别
在扩展之前必须先阅读相应的代码,尤其是内存分配的代码
回复
hewittlee 2004-08-28
up
回复
CityFantom 2004-08-28
观注!!
回复
conghonglei 2004-08-28
请问 shornmao(毛豆子[死猫]) basic_string 针对 char 的特化在那里?

stl 的算法都是由 traits偏特化的吧
回复
mygodtoo 2004-08-17
所谓扩冲,主要是conteration && algorithm

sample:
template<class In, class Out. class pred>
Out copy_if(In _F, In _L, Out res, Pred p)
{
while(_F != _L){
if(p(*_F)) *res++ = *_F;
___F
}

you wil find in stl no find_if
you can do it;
}
回复
shornmao 2004-08-17
这样扩展是不对的。
要么直接从string派生,这样比较简单。
如果想从basic_string派生,那么就比较麻烦了,那样就要使用模板的方式。
像NetLinux(笑天-www.laughsky.com)那样肯定是不行的,而要
template </*这里面照抄basic_string的*/>
my_basic_string : public basic_string</*把上面的模板参数照抄一遍*/>
可是接下来对于my_basic_string<char>的特化,就麻烦了,原先basic_string<char>的特化都不存在了,只能自己在加上去。
所以,不妨直接从string派生,这样就应该非常容易才行。
尤其是对于字符串解析来说,你不会指望同时解析char和wchar_t两种字符吧。
回复
ykj76 2004-08-17
直接从string派生??
class MyString : public std::string{}

这样的MyString好像什么都不能干
回复
jeckyz 2004-08-16
有人已经这么做了,楼主可以到www.codeproject.net上找一找,我记得其中有两个工程是用std::string实现CString的,还比较安全实用。
回复
expert2000 2004-08-16
帮顶,学习,楼主给点分我就能升级。
回复
ixMind 2004-08-16
一般这种扩展有以下几种方式:
1。修改源代码,增加新的功能
2。Introduce Foreign Method,如
class StringUtility {
public:
static string betweenTwoChar(...);
};
3。Introduce Local Extension,如:定义新的string类,继承
basic_string/string/wstring类,并让两者之间可以相互转换
我们可以根据实际情况选择对应的方法

另外对于复杂的字符串解析,我想还是使用regular expression比较好,如果完全
使用string来实现解析,那会很繁琐很容易出错

还有,问一下大家对于trim和compareNoCase等一些常规操作是怎么弄的


回复
加载更多回复
相关推荐
发帖
工具平台和程序库
创建于2007-09-28

2.4w+

社区成员

C/C++ 工具平台和程序库
申请成为版主
帖子事件
创建了帖子
2004-07-18 05:55
社区公告
暂无公告