2

我想substr在我制作的字符串类中用 C++ 创建一个方法。

string 类当然是基于 C 风格的字符串,我负责内存管理。

我想编写一个substr(start, length)可以正常工作的函数:

CustomString mystring = "Hello";

cout << mystring.substr(0,2); // will print "He"

而且也是这样:

mystring.substr(1,3) = "DD"; // mystring will be "HDDo"

请注意,即使我得到一个 3 个字符长的子字符串,我只输入了 2 个字符,输出字符串仍然是 HDDo。

知道如何完成这项工作吗?

谢谢!

4

3 回答 3

6

为了支持这一点,您可能必须编写您的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);
}
于 2009-10-16T19:37:57.863 回答
0

大概你想substr返回一个字符串,而不是其他一些代理类。因此,您需要使您的字符串类能够保存指向其自己的字符串数据副本的指针以及指向创建它的另一个字符串对象的指针(作为 的返回值substr),以及有关哪个部分的信息创建它的字符串。

substr当您调用从另一个调用返回的字符串时,这可能会变得相当复杂substr

复杂性可能不值得界面的吸引力。

于 2009-10-16T19:44:40.150 回答
0

第一个要求很简单;查找运营商的标准实现。

松散地,c_string& substr(int, int)

第二部分,没有那么多,我不认为。我相信它看起来会很相似。不过,我会考虑一下,并在周末回复您。

于 2009-10-16T19:45:21.300 回答