Pour cela, vous devrez probablement écrire votre substr()
pour renvoyer un objet proxy qui garde la trace de la partie de la chaîne d'origine à laquelle il est fait référence. L'objet proxy surchargera operator=
et remplacera la sous-chaîne référencée par la nouvelle sous-chaîne.
Modifier en réponse à des commentaires: l'idée d'un proxy est qu'il est assez similaire à la classe pour laquelle il est un proxy que renvoyer un proxy est toujours une opération fermée - du point de vue de l'utilisateur, tout ce qui est visible est le type d'objet original, mais il a des capacités qui ne seraient pas possibles (ou seraient beaucoup plus difficiles à implémenter) sans le proxy. Dans ce cas, nous la classe proxy serait privée à la classe de chaîne, de sorte que l'utilisateur ne pourrait jamais créer une instance de la classe proxy, sauf en tant que temporaire. Ce temporaire peut être utilisé pour modifier sa chaîne parent si vous lui attribuez. L'utilisation du proxy de toute autre manière donne simplement une chaîne. Pour ce que cela vous achète en essayant de tout faire à l'intérieur de la chaîne d'origine: chaque objet proxy est un objet temporaire - le compilateur peut/will/ne garder trace de la façon de créer des temporaires si nécessaire, les détruit correctement à la fin d'une expression complète, etc. Le compilateur conserve également la trace de la sous-chaîne à laquelle une assignation particulière fait référence, la convertit automatiquement en chaîne lorsque nous essayons d'utiliser sa valeur, et ainsi de suite. Autrement dit, le compilateur gère presque tout le dur labeur impliqué.
Voici quelques codes de travail. La classe de chaînes qui l'entoure est assez minime (par exemple, elle n'a aucune capacité de recherche). Je m'attendrais à ajouter un montant raisonnable à une version utile de la classe de chaînes. La classe de proxy, cependant, est complète - je ne m'attendrais pas à voir cela changer beaucoup (le cas échéant) dans une version complète de la classe de chaîne.
#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
Edit 2: En ce qui concerne les sous-chaînes de sous-chaînes vont, ça dépend. La situation qui n'est pas actuellement couverte est si vous souhaitez affecter à une sous-chaîne d'une sous-chaîne, et qu'elle affecte la chaîne d'origine. Si vous voulez quelque chose comme x=y.substr(1,4).substr(1,2);
cela fonctionnera bien tel quel. Le premier proxy sera converti en une chaîne, et le second sous-réseau sera appelé sur cette chaîne.
Si vous le souhaitez: x.substr(1,4).substr(1,2) = "whatever"
; cela ne fonctionnera pas actuellement.Je ne suis pas sûr qu'il accomplit beaucoup, mais en supposant qu'il fait, l'ajout de soutien, il est assez minime - vous souhaitez ajouter un membre substr à proxy:
proxy substr(size_t start, size_t len) {
return proxy(parent, pos+start, len);
}
Juste ce dont C++ a besoin. * Une autre classe de chaînes. – jalf
"... l'écriture de classes de chaînes est l'un des sports d'intérieur les plus populaires parmi les programmeurs C++." (P.J. Plauger, "Le projet de bibliothèque standard C++", p345) – sbi
* I * a écrit une classe de liste liée il y a un an ou deux. Parce que je savais que C++ * avait besoin d'une autre classe LL. –