std::string
本身没有。
有各种替代方案,或多或少优雅,或多或少利弊。让我试着比较一下
封装
可能是最干净的解决方案:创建一个包含 std::string 的类,该类可以采用执行转换的 ctor 和分配。
- 问题:std::sting 有超过一百种方法:如果您希望您的类公开所有方法...准备编写所有软管函数只是为了调用包装的函数。这是一个干净的“生产力问题”,似乎没有 OOP 狂热者照顾......可能是由键入的字符支付...... :-)
- 优点:运行时多态(std::string 不支持)不会意外工作,因此代码更安全。
“部分”换行
和以前一样,但只涉及一些重要的方法或需要一些显式编码。
一个典型的实现可以是:
可:
class llstring
{
public:
//just esplicitate a default
llstring() :m() {}
//this wors for all the std::string contructors but the ones specifically defined here
template<class T, class... TT>
llstring(T&& t, TT&&... tt) :m(std::forward<T>(t), std::forward<TT>(tt)...)
{}
// copy and move defaulted: just call the memebr ones
llstring(const llstring&)=default;
llstring(llstring&&) =default;
//impose conversion
llstring(const std::string& s) :m(lowercase(s)) {}
llstring(const char* s) :m(lowercase(s)) {}
//assign and transfer defaulted
llstring& operator=(const llstring&)=default;
llstring& operator=(llstring&&)=default;
//impose conversion
llstring& operator=(const std::sting& s) { m = lowercase(s); return *this; }
llstring& operator=(const char* s) { m = lowercase(s); return *this; }
//gets the "value"
const std::string& str() const { return m; }
private:
std::string m;
};
此类本身无法进行任何算法和操作,但可以std::string
通过调用str()
. 并且可以接受任何 std::string 结果,通过转换获得。
可能是重新编码和维护风险之间的良好折衷
继承
std::string 作为基础,而不是成员。代码与上面类似(您必须提供一种在构造或分配上进行转换的方法)
优点:原始 std::string 的接口和行为是自动公开的,因此所有 std::string 方法都可以工作并且可以访问。
中性:从 std::string 向前(通过设计)和向后(通过基本继承)转换都有效。这可能会导致某些可能无法通过 llstring 的操作出现歧义。本身不是问题,但您必须了解函数名称解析和绑定是如何完成的。语言是明确指定的,但它是任何普通程序员并不总是知道的语言之一。
缺点: llstring 公开了一个关于 std::string 的多态行为,它不会在多态方面表现出 llstring 的行为(没有方法是虚拟的,包括析构函数),因此你绝不能在 std::string* 上调用 delete (它是未定义的行为,如果它指向一个'llstring`)。
考虑到llstring
和 string 都是值类型,这通常不应该发生(30 年来我从未写过一个new std::string
or delete pstring
)。但这无论如何都会抓住 OOP 狂热者的所有咆哮,他们假装经典的 OOP 规则也适用于 string-s,即使它们不是 OOP 对象。
但是还有另一个-恕我直言更微妙的风险:在 llstring 和 string 之间的复合表达式中,所有中间结果都将是 string。并且中间操作不会在两者之间转换。所有这些都是隐含的。同样,语言规范定义明确,但控制一切可能并不容易。对尚未分配的中间结果的搜索可能会失败......因为内部意外的大写字母。
反向转换
不完全是你问的,但是......可能会更好地解决问题。
而不是“在返回目的地时转换”,而是“在离开源时转换”:
编写一个包装器(如上面的“部分扭曲”),它不是从字符串隐式转换并具有显式 str() 函数,而是从字符串显式构造(即使没有转换)并具有隐式转换为字符串 ( operator std::string() { return lowercase(m); }
)
这与您所要求的相反。如果允许存在大写字符串的点的数量很少尊重程序中的总字符串(您可以假设始终为小写)并且如果您可以授予您可以实现的所有 std::string 操作,那将是很好的小写字符串值永远不会生成大写字符串。
编辑:char_traits 解决方案
在Nawaz 帖子之后添加:
该解决方案尝试通过使 char 遵守另一种语义来改变行为(而不是value )。
- 优点:简单,不需要大包装。快速编码。
- 缺点:可能不完全符合预期:由于 std::string 函数都是可访问的,并且由于复制可能不是更改字符串内容的唯一方法,因此(在任何情况下)您都不会被授予大写字符它。除非您可以授予该副本,否则该副本将是更改字符串值的唯一方法。
注意:就像 一样string
,也char_traits
没有虚拟析构函数,但是,与字符串不同,没有 OOP 狂热者通常会大喊从它的继承。如果被问到,很可能会说“char_traits 上不会有动态分配”。再见连贯性。
综上所述
没有“低成本”的“完美解决方案”。他们都在某个阶段不完美