CString-clone Using Standard C++

本文介绍了一种名为CStdString的模板类,它结合了MFC的CString类的易用性和C++标准库中basic_string类的强大功能。CStdString不仅保留了基本字符串的所有特性,还提供了CString类的API,使得开发者可以更方便地进行字符串操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Introduction

As much as I use and appreciate the Standard C++ Library, I've never liked its string template - basic_string<>. At times it seems the designers went out of their way to make it difficult to use.

On the other hand, I've always loved the ease of use of MFC's CString class. It checks for NULL pointers, implicitly converts to const TCHAR*, and has some very handy member functions (Format, Load, etc) that make string programming a breeze. But of course, I don't want to use MFC anymore. In fact, I don't want to rely on any proprietary library because I want portability.

Therefore I decided to combine the best of both worlds and create:

CStdString

This is a class (a template instantiation actually) that derives from from basic_string<TCHAR>. To the basic_string it adds the entire CString API. You get CString ease of use with 100% basic_string compatiblity. In short, a CStdString object is a basic_string that (with very few exceptions (noted below) it is also a drop-in replacement for CString. The best part of this is that both APIs (basic_string and CString) are well known and well documented.

I originally submitted this article to another code site (which shall remain nameless :)) a few years ago. I like CodeProject so much I thought I'd submit it here too. I have used this class in almost every professional project I've done over the past 4 years. It has proven to be the single most useful piece of code I've ever written. It is also extensively debugged. I hope you like it. If you ever have any problems with it, please e-mail me. I'm happy to help.

I provided a simple source application here to prove some of the CString functions work but it's really just a token. The list of sample projects out there that use CString and/or basic_string is massive.

Features:

  • Drop in Replacement for CString (see below for exceptions)
  • Two instantiations available at all times -- wchar_t-based version CStdStringW and char-based version CStdStringA. The name CStdString is just a typedef of one of these two.
  • Safely checks for NULL string pointer inputs (like CString) in all functions
  • Extra constructors and assignment operators to automatically convert between wide (wchar_t-based) and thin (char-based) strings for you.
  • Implicit conversion to c_str(). The C++ Committee doesn't like this but I sure do.
  • Builds on several platforms, including Windows, Unix and Linux. Works with several implementations of the Standard C++ Library, including Dinkumware, GNU, CodeWarrior, and STLPort.
  • Win32 builds give you some extra goodies like UNICODE/MBCS conversion macros (just like MFCs) as well as member functions for persisting CStdString objects to and from DCOM IStreams.
  • Makes no use of any implementation details of the base class template (basic_string)
  • The derived template adds no member data to basic_string and adds no virtual functions

There are a couple of issues about this code of that I should point out.

CString Compatibility

I was unable to exactly reproduce the CString API. There are a two functions that both CString and basic_string; share, but implement differently. In these cases, I felt it best to make CStdString behave like basic_string (the base class) rather than CString. To be specific.

  • CStdString::operator[] returns characters by value (unlike CString which returns them byreference<)
  • the constructor that takes a character and a count takes them in the order (count, value) which is the opposite of the order CString declares them. That's the order that basic_string<>; needs and it was impossible to implement both versions.

There were also two CString functions I could not implement at all -- LockBuffer and UnlockBuffer.

Deriving From basic_string<>

The template I wrote derives from basic_string, a class template without a virtual destructor. Any introductory text to C++ will tell you that it is dangerous to derive from a class without virtual a destructor. It can lead to behavior that is undefined. So if you were to code the following (deleting a CStdStringA through a pointer to the base class) you would technically get undefined behavior

// assign DERIVED object to  BASE pointer
std::string* pstr = new CStdStringA("Hi"); 

// delete  DERIVED through BASE class pointer -- UNDEFINED
delete pstr;   

Personally, I don't think this is much of an issue. I mean really how often do you actually do this with string objects? I have rarely (if ever) needed to dynamically allocate a string object on the heap. And if I ever do, I won't using a base-class pointer. So if you don't do this, you'll never have to worry. In fact, even if you do code this way, I doubt you'll have any problems with CStdString. I can tell you that at least with Microsoft Visual C++, even the above code runs just fine with no errors or memory leaks. I doubt many other compilers would give you problems either. However my doubt does not impose reality on the C++ world. Caveat Emptor.

About Joe O'Leary


I've been a software developer since 1990.

While my main page is out of date (and I have therefore blanked it), you can read about the CStdString pages here

http://home.earthlink.net/~jmoleary/stdstring.htm

Click here to view Joe O'Leary's online profile.

 
### C++ 中数组数据复制方法 在 C++ 中有多种方式可以实现将一个数组的数据复制到另一个数组。以下是几种常见的做法: #### 使用循环逐个赋值 最基础的方式是通过 `for` 循环来遍历源数组并将每个元素依次赋给目标数组。 ```cpp #include <iostream> using namespace std; int main(){ int source[] = {1, 2, 3, 4, 5}; int destination[5]; for(int i=0; i<5; ++i){ destination[i] = source[i]; // 复制操作 } cout << "Copied elements:" << endl; for (auto& elem : destination) { cout << elem << ' '; } } ``` 此代码片段展示了如何利用简单的索引访问来进行一对一的元素拷贝[^1]。 #### 利用标准库函数 memcpy 或者 memmove 对于原始类型的简单数组,还可以采用内存级别的复制手段如 `memcpy()` 函数,它能够高效地完成大块连续存储区域之间的转移工作;而当存在重叠区间时,则应该选用更安全可靠的 `memmove()` 来代替。 ```cpp #include <cstring> // 包含了 memcpy 和 memmove 的头文件 #include <iostream> int main(){ char srcStr[] = "HelloWorld"; char destStr[sizeof(srcStr)]; memcpy(destStr, srcStr, sizeof(srcStr)); // 不处理重叠情况下的快速复制 cout << "After copying with memcpy(): "; puts(destStr); return 0; } ``` 这段程序说明了怎样借助于 `<cstring>` 库中的工具简化并加速批量传输过程。 #### 借助 STL 容器和算法 如果希望编写更加现代化且可移植性强的应用程序,那么推荐考虑使用来自 Standard Template Library(STL) 的容器类(比如 vector)以及关联的标准模板库<algorithm>里的通用算法——copy_n() 或者 copy_if() 等等。 ```cpp #include <algorithm> // 提供了各种迭代器支持的操作 #include <array> // 固定大小序列化集合类型 #include <iostream> void printArray(const std::array<int, 5>& arr){ for(auto val : arr) std::cout << val << ' '; } int main(){ std::array<int, 5> original{10, 20, 30, 40, 50}, clone{}; std::copy(original.begin(), original.end(), clone.begin()); // 运用了STL提供的高级接口 printArray(clone); } ``` 上述例子体现了运用现代C++特性所带来的简洁性和灵活性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值