std::string class 用 cstring API 包装(属性 代理模式)

std::string class wrapped with cstring API (property proxy pattern)

我想使用 std::strings 将遗留代码库中使用 cstrings 的静态数据结构转换为动态数据结构。问题是,现在,在我们的代码库中调整所有使用它们的函数是不可行的。

我建议使用包装器 class(属性 代理模式),它在内部使用 std::string 公开 cstring API。这将允许使用 cstring 函数(strcpy、strlen、memset 等)并使数据结构向后兼容。这是我目前所拥有的:

原始数据结构:

struct data
{
    char property1[20];
    char property2[20];
}

新结构:

struct data
{
    CStringProperty property1;
    CStringProperty property2;
}

包装器class:

class CStringProperty
{
public:
  CStringProperty(){}
  CStringProperty(std::string& value) : _value{value}{}
  CStringProperty(char* value) : _value{value}{}

  CStringProperty& operator=(std::string value)
  {
      _value = value;
      return *this;
  }

  CStringProperty& operator=(char* value)
  {
      std::string valueStr = value;
      return operator=(valueStr);
  }

  operator std::string()
  {
      return _value;
  }

  operator char*()
  {
      return &_value[0];
  }

  char& operator[](int i)
  {
      return _value[i];
  }

  std::string to_str()
  {
      return _value;
  }

private:
  std::string _value;
  friend std::ostream& operator<<(std::ostream& os, CStringProperty& value);
};

std::ostream& operator<<(std::ostream& os, CStringProperty& value)
{
    return os << value.to_str();
}

测试

int main()
{
    CStringProperty a= "Hello";
    std::cout << "Test 1: " << a << std::endl;  // Works

    CStringProperty b;
    b = a;
    std::cout << "Test 2: " << b << std::endl; // Works

    CStringProperty c;
    char d[10] = "Hello";
    c = d;
    std::cout << "Test 3: " << c << std::endl; // Works

    char* e = a;
    std::cout << "Test 4: " << e << std::endl; // Works

    CStringProperty f;
    std::cout << "Test 5: " << f << std::endl;  // Works

    CStringProperty g = "Hello";
    g[0] = 'X';
    std::cout << "Test 6: " << g << std::endl;  // Works

    CStringProperty h = "Hello";
    std::cout << "Test 7: " << std::to_string(strlen(h)) << std::endl;  // Works

    CStringProperty p = "hello";
    strcpy(p,"bye");
    std::cout << "Test 8.1: " << std::to_string(strlen(p)) << std::endl; // Works
    std::cout << "Test 8.2: " << p << std::endl; // Doesn't work

    CStringProperty q;
    strcpy(q,"bye");
    std::cout << "Test 9.1: " << std::to_string(strlen(q)) << std::endl; // Works
    std::cout << "Test 9.2: " << q << std::endl; // Doesn't work

    return 0;
}

我知道 std::string::data() 暴露了底层的 cstring,但是这个 returns 是 const char*,所以它显然只是为了阅读目的。使用 const_cast 我想会类似于我在上面所做的并导致未定义的行为。

如果知道没有办法做到这一点,我会非常气馁,因为这意味着真正巨大的重构工作,所以我感谢任何帮助或想法。

9.2 和 8.2 不起作用的原因是因为 std::string 有一个 size_ 数据成员。 strcpy函数不修改它。

您可以使用 friend 函数(或常规函数)解决此问题。

class CStringProperty
{
public:
  CStringProperty(){}
  CStringProperty(std::string const& value) : _value{value}{}
  CStringProperty(char const* value) : _value{value}{}

  CStringProperty& operator=(std::string value)
  {
      _value = value;
      return *this;
  }

  CStringProperty& operator=(char* value)
  {
      std::string valueStr = value;
      return operator=(valueStr);
  }

  operator std::string()
  {
      return _value;
  }

  operator char const*()
  {
      return _value.c_str();
  }

  char& operator[](int i)
  {
      return _value[i];
  }

private:
  std::string _value;

  friend std::ostream& operator<<(std::ostream& os, CStringProperty const& value)
  {
      return os << value._value;
  }

  friend void strcpy(CStringProperty& value, char const* src)
  {
    value._value = src;
  }

  friend size_t strlen(CStringProperty const& value)
  {
    return value._value.size();
  }
};

另一个问题是您没有在需要的地方使用 const。而且您还按值传递 std::string,这可能会影响性能。