3

まず、私の懸念を理解するために、私が準備した次の 2 つのコード セグメントを見てください。

struct Quaternion
{
public:

    float X, Y, Z, W;

    Quaternion(float x, float y, float z, float w)
        :
        X(x), Y(y), Z(z), W(w)
    {}

    void Normalise()
    {
        float num = (((this->X * this->X) + (this->Y * this->Y)) +
            (this->Z * this->Z)) + (this->W * this->W);
        float num2 = 1.0f / (static_cast<float>(std::sqrt(static_cast<double>(num))));
        this->X *= num2;
        this->Y *= num2;
        this->Z *= num2;
        this->W *= num2;
    }

    void Conjugate()
    {
        this->X = -this->X;
        this->Y = -this->Y;
        this->Z = -this->Z;
    }
};

上記は、タイトルで言及しているクラス内の「ローカル メソッド」です。次に、クラス内の「静的メソッド」の意味を見てみましょう。

struct Quaternion
{
public:

    float X, Y, Z, W;

    Quaternion(float x, float y, float z, float w)
        :
        X(x), Y(y), Z(z), W(w)
    {}

    static Quaternion& Normalise(Quaternion& quat)
    {
        float num = (((quat.X * quat.X) + (quat.Y * quat.Y)) +
            (quat.Z * quat.Z)) + (quat.W * quat.W);
        float num2 = 1.0f / (static_cast<float>(std::sqrt(static_cast<double>(num))));
        // Assuming operator= overloaded..
        quat = Quaternion(quat.X * num2, quat.Y * num2, quat.Z * num2, quat.W * num2);
        return quat;
    }

    static Quaternion& Conjugate(Quaternion& quat)
    {
        // Assuming operator= overloaded..
        quat = Quaternion(-quat.X, -quat.Y, -quat.Z, quat.W);
        return quat;
    }
};

私の質問は..トレードオフは何ですか? の効果?ローカル メソッドではなくこれらの静的クラス メソッドを使用するには。どちらも同様の使用法があります。

編集: *.ToString 機能は無視してください。これは疑似コードです。それが何をするか想像できると思います。したがって、生の X、Y、Z、W 値を出力するだけなので、その実装は冗長です。

「ローカル メソッド」クラスの使用法:

int main()
{
    Quaternion testQuat(6.0f, 6.0f, 6.0f, 1.3f);

    std::cout << testQuat.ToString(); // (6, 6, 6, 1.3)

    testQuat.Conjugate();

    std::cout << testQuat.ToString(); // (-6, -6, -6, 1.3)

    return 0;
}

「静的メソッド」クラスの使用法:

int main()
{
    Quaternion testQuat(6.0f, 6.0f, 6.0f, 1.3f);

    std::cout << testQuat.ToString(); // (6, 6, 6, 1.3)

    testQuat = Quaternion::Conjugate(testQuat);

    std::cout << testQuat.ToString(); // (-6, -6, -6, 1.3)

    return 0;
}

違いは何ですか?これらはオブジェクトではなく静的メソッドです。どちらが好ましいですか?それは単にデザインの選択の問題ですか?

4

3 に答える 3

3

それらは2つのまったく異なるものです。そのうちの 1 つはOOPのようにオブジェクトを変更し、もう 1 つは機能的なスタイルの別のオブジェクトを返します。それが私の選択だった場合、両方のユースケースがあるため、両方を保持します。そして、関数スタイルをメンバー関数に基づくフリー関数として実装します。つまり、次のようになります。

Quaternion normalize( Quaternion quat )
{
    quat.normalize();
    return quat;
}

[ここでは明示的にquat値を取っており、コピー省略の可能性があります]

静的実装が間違っていることに注意してください。一時的なものへの参照を返しています。これは未定義の動作です。コンパイラから警告が表示され、運が良ければランタイム クラッシュも発生します。

于 2012-12-28T19:29:05.453 に答える
1

constまず、MSVC++ にはエラーがあり、一時オブジェクトを非参照にバインドできると思いますが、2 番目のアプローチはコンパイルしないでください。追加してもconst&関数は改善されません。呼び出し元が一時的な参照を取得するため、機能しません。実装は以上です。

インターフェースの設計に関しては、実際のトレードオフはstaticメンバー間ではなく (必要に応じてメンバーを追加することもできます)、パラメーターを取らない関数がオブジェクト自体を変更する必要があるか、それに応じて変更されたオブジェクトを返す必要があるかどうかです。

// return a copy:
Quaternion Quaternion::conjugate() const {
    return Quaternion(-this->X, -this->Y, -this->Z, this->W);
}

// modify the object itself:
void Quaternion::conjugate() {
    this->X = -this->X;
    this->Y = -this->Y;
    this->Z = -this->Z;
}

これら 2 つのオーバーロードは実際には同じクラスに存在できますが、両方を提供することはありません。どちらが好ましいかはインターフェースの選択です。私は個人的に後者を好み、おそらくstaticオブジェクト自体を変更するメンバーを作成します。

/* static */ void Quaternion::conjugate(Quaternion& object) {
    object = object.conjugate();
}
于 2012-12-28T19:38:27.023 に答える
0

2つのアプローチの違いに関する他の回答に加えて、単体テストで使用する場合、静的メソッドをモック/スタブするのは困難です。

たとえば、Quaternion を使用する ClassThatUsesQuaternion という名前のクラスがあるとします。Quaternion に多くの静的メソッドがある場合、常に実際のデータが得られます。一方、Quaternion メソッドを仮想メソッドに変換すると、すべてのメソッドを再定義して、制御下で環境テストを作成できます。gmock のようなモック フレームワークを追加して、期待値を設定することもできます。

于 2012-12-28T19:43:31.713 に答える