为了支持这一点,您可能必须编写您的substr()
方法来返回一个代理对象,该对象跟踪原始字符串的哪一部分被引用。代理对象将重载operator=
,并在其中将引用的子字符串替换为新分配的子字符串。
编辑以回应评论:代理的想法是它与作为代理的类足够相似,返回代理仍然是一个封闭的操作——即从用户的角度来看,所有可见的都是对象的原始类型,但它具有没有代理就不可能(或者更难以实现)的功能。在这种情况下,我们的代理类对字符串类来说是私有的,所以用户永远不能创建代理类的实例,除非是临时的。如果您分配给它,则该临时可用于修改其父字符串。以任何其他方式使用代理只会产生一个字符串。
至于这会给你带来什么,而不是尝试在原始字符串中执行所有操作:每个代理对象都是一个临时对象——编译器可以/将/确实跟踪如何根据需要创建临时对象,并在结束时正确销毁它们完整的表达式等。编译器还跟踪特定赋值引用的子字符串,当我们尝试使用它的值时自动将其转换为字符串,等等。简而言之,编译器处理了几乎所有涉及的繁重工作。
这是一些工作代码。周围的字符串类非常小(例如,它没有搜索能力)。我希望在有用的字符串类版本中添加相当数量的内容。然而,代理类是完整的——我不希望在字符串类的功能完整版本中看到它有很大的变化(如果有的话)。
#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator>
class string {
std::vector<char> data;
public:
string(char const *init) {
data.clear();
data.assign(init, init+strlen(init));
}
string(string const &s, size_t pos, size_t len) {
data.assign(s.data.begin()+pos, s.data.begin()+pos+len);
}
friend class proxy;
class proxy {
string &parent;
size_t pos;
size_t length;
public:
proxy(string &s, size_t start, size_t len) : parent(s), pos(start), length(len) {}
operator string() { return string(parent, pos, length); }
proxy &operator=(string const &val) {
parent.data.erase(parent.data.begin()+pos, parent.data.begin()+pos+length);
parent.data.insert(parent.data.begin()+pos, val.data.begin(), val.data.end());
return *this;
}
};
proxy substr(size_t start, size_t len) {
return proxy(*this, start, len);
}
friend std::ostream &operator<<(std::ostream &os, string const &s) {
std::copy(s.data.begin(), s.data.end(), std::ostream_iterator<char>(os));
return os;
}
};
#ifdef TEST
int main() {
string x("Hello");
std::cout << x << std::endl;
std::cout << x.substr(2, 3) << std::endl;
x.substr(2, 3) = "DD";
std::cout << x << std::endl;
return 0;
}
#endif
编辑2:就子字符串的子字符串而言,这取决于。当前未涵盖的一种情况是,如果您要分配给子字符串的子字符串,并使其影响原始字符串。如果您想要类似的东西,x=y.substr(1,4).substr(1,2);
它会按原样正常工作。第一个代理将被转换为字符串,第二个 substr 将在该字符串上调用。
如果你想:x.substr(1,4).substr(1,2) = "whatever"
; 它目前不起作用。我不确定它完成了多少,但假设它完成了,支持它的添加是相当少的——你会添加一个 substr 成员到代理:
proxy substr(size_t start, size_t len) {
return proxy(parent, pos+start, len);
}