1

すべて。私はC++にかなり慣れていないので、C ++で小さなライブラリ(主に自分のプロジェクト用)を作成しています。型階層を設計する過程で、代入演算子を定義する問題に遭遇しました。

この記事で最終的に到達した基本的なアプローチを採用しました。つまりMyClass、クラスから派生した階層内のすべてのクラスに対して、次のBaseように2つの代入演算子を定義します。

class MyClass: public Base {
public:
    MyClass& operator =(MyClass const& rhs);
    virtual MyClass& operator =(Base const& rhs);
};

// automatically gets defined, so we make it call the virtual function below
MyClass& MyClass::operator =(MyClass const& rhs);
{
    return (*this = static_cast<Base const&>(rhs));
}

MyClass& MyClass::operator =(Base const& rhs);
{
    assert(typeid(rhs) == typeid(*this)); // assigning to different types is a logical error
    MyClass const& casted_rhs = dynamic_cast<MyClass const&>(rhs);
    try {
        // allocate new variables
        Base::operator =(rhs);
    } catch(...) {
        // delete the allocated variables
        throw;
    }
    // assign to member variables
}

私が関わっているのは、型の同等性のアサーションです。私はライブラリを書いているので、おそらく最終結果からアサーションがコンパイルされるので、これにより、次のようなスキームを使用するようになりました。

class MyClass: public Base {
public:
    operator =(MyClass const& rhs); // etc
    virtual inline MyClass& operator =(Base const& rhs)
    {
        assert(typeid(rhs) == typeid(*this));
        return this->set(static_cast<Base const&>(rhs));
    }
private:
    MyClass& set(Base const& rhs); // same basic thing
};

しかし、コンパイル時に型を確認できるかどうか疑問に思っていました。Boost.TypeTraitsを調べて、やることで近づきましたBOOST_MPL_ASSERT((boost::is_same<BOOST_TYPEOF(*this), BOOST_TYPEOF(rhs)>));が、rhsは派生クラスではなく親クラスへの参照として宣言されているため、チョークしました。

考えてみると、私の推論はばかげているようです。関数がインラインであるため、実際のパラメーター自体をチェックできることを期待していましたが、もちろん、プリプロセッサーは常にコンパイラーの前に実行されます。しかし、コンパイル時にこの種のチェックを強制できる他の方法を誰かが知っているかどうか疑問に思いました。

4

2 に答える 2

7

このアサートをコンパイル時に実行することはできません。これは、実行時の型が実行時までわからないという単純な理由からです。

assert(typeid(rhs) == typeid(*this));
return this->set(static_cast<Base const&>(rhs));

非インライン バージョンでは、dynamic_cast. アサーションに違反した場合に未定義の動作ではなく、明確に定義されたエラーが発生するように、これを保持します。

これを行うと、アサーションは過度に制限的であるか、無意味になります。は、デバッグ ビルドとリリース ビルドの両方で例外dynamic_castをスローします。bad_castこれはあなたが望むものです。

個人的には、ポリモーフィック割り当ての問題全体に疑問を投げかけます。Scott Meyers の効果的な C++ のアドバイスに従い、継承階層内のすべての非リーフ ノードを抽象化します。次に、基本クラスの割り当て演算子を保護された非仮想にすることができます。

これにより、派生クラスの代入演算子でそれらの実装を使用できますが、クライアントはオブジェクトをスライスできなくなります。クライアント クラスが基本クラスの参照またはポインタしか持たない場合、とにかくクラスに代入を試みる必要があるかどうかは疑問です。もしそうなら、彼らはキャストと型の安全性の保証に責任を持つべきです。

于 2010-04-12T07:02:26.613 に答える
0

コンパイル時に物事を決定したい場合は、動的ポリモーフィズム(仮想関数など)は適切なツールではありません。私は一般的に、動的ポリモーフィズムを「通常の値型」が持つもの(代入演算子など)と混合する必要性を認識していません。たぶん、具体的で非多形のクラスがあなたの場合に最もよく機能するものです。しかし、クラスで何をしようとしているのかについて何も言わなかったので、わかりにくいです。

于 2010-04-12T06:53:11.473 に答える