2

substr作成した文字列クラスにC++でメソッドを作成したいと思います。

文字列クラスはもちろん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:部分文字列の部分文字列に関する限り、それは異なります。現在カバーされていない1つの状況は、サブストリングのサブストリングに割り当てて、元のストリングに影響を与える場合です。このようなものが必要な場合は、x=y.substr(1,4).substr(1,2);そのままで問題なく動作します。最初のプロキシは文字列に変換され、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 に答える