4

ac 構造体をラップする c++ クラスを書きたいと思っています。ac 構造体の簡単な例を次に示します。

struct POINT {
  long x;
  long y;
}

今、私はこの次のクラスを想定していますが、それが「パフォーマンス」なのか、C++ スタイルが良いのかはわかりません。不要な変数や関数呼び出しを使用したくありませんでした。私のコードを改善していただければとてもうれしいです:)。

このクラスの背後にある基本的な考え方は、構造体の単なるラッパー/ハンドラーであるということです。これが、プライベート データを直接変更できる理由setStructgetStructあり、それは単なるポインタであるということです。他のメンバーの名前は常にset<Attribute>およびget<Attribute>です。

setStruct私が考えることができる唯一の欠点を使用する場合、スコープが原因で構造体が削除される可能性があるため、ポインターが「無効」になる可能性があります。

namespace wrapper {
class POINT {
  ::POINT * POINT_;

public:
  POINT() {
    POINT_ = new ::POINT;
  }
  ~POINT() {
    delete POINT_;
  }
  inline void setX( long x ) {
    POINT_->x = x;
  }
  inline long getX() {
    return POINT_->x;
  }
  inline void setY( long y ) {
    POINT_->y = y;
  }
  inline long getY() {
    return POINT_->y;
  }
  inline void setStruct(::POINT * __POINT) {
    POINT_ = __POINT;
  }
  inline ::POINT * getStruct() {
    return POINT_;
  }
};
}
4

2 に答える 2

4

この場合、構成の代わりに継承を使用する方がよい場合があります。追加のリソースを管理する必要がなくなり、POINT 構造全体のアクセサーとミューテーターを必要とする代わりに、「ラッパー」が POINT として機能できるようになります。

namespace wrapper {
    class Point : public ::POINT
    {
    public:
        Point() { }
        ~Point() { }

        // The following accessors/mutators may not be necessary.
        // They can however be handy with code that requires a pointer to
        // member function (i.e. transformations)
        void setX(long nx) { x = nx; }
        long getX() { return x; }
        void setY(long ny) { y = ny; }
        long getY() { return y; }

        // copy assignment operators
        Point& operator=(const POINT& p)
        {
            x = p.x;
            y = p.y;
            return *this;
        }

        Point& operator=(const Point& p)
        {
            x = p.x;
            y = p.y;
            return *this;
        }
    };
}

のメンバーへの直接アクセスを防ぎたい場合は、POINTプライベート継承を使用できます。Point変換演算子を指定して、 からへの暗黙的な変換を許可することもできますPOINT。これによりメンバー関数が置き換えられますが、引数としてPOINT* getStruct()必要な関数で簡単に使用できます。POINT

namespace wrapper {
    // Use private inheritance to prevent direct access to the
    // members of POINT
    class Point : private POINT
    {
    public:
        Point() { }
        ~Point() { }

        // Copy constructor
        Point(const ::POINT& p) { x = p.x; y = p.y; }

        // Accessor/mutators
        void setX(long nx) { x = nx; }
        long getX() { return x; }
        void setY(long ny) { y = ny; }
        long getY() { return y; }

        // Allow implicit conversions to POINT* when necessary
        // Replaces getStruct()
        operator ::POINT*() { return this; }
        operator const ::POINT*() const { return this; }

        // Copy assignment operators
        Point& operator=(const POINT& p)
        {
            x = p.x;
            y = p.y;
            return *this;
        }

        Point& operator=(const Point& p)
        {
            x = p.x;
            y = p.y;
            return *this;
        }
    };
}

extern "C" void someCFunction(POINT *);

int main()
{
    POINT cp;
    wrapper::Point p;

    p.x = 0; // FAIL
    p.setX(0); // OK
    p = cp; // OK

    // No need to call getPoint().
    someCFunction(p);
}

注: の使用inlineは不要なので削除しました。クラス定義内で定義された関数は既にインライン化されています ($7.1.2/3 を参照)。思い出させてくれたクリスに感謝します。

于 2013-07-03T17:40:54.823 に答える
0

既に述べたように、 + 大文字_POINTで始まるため予約名です。_

型名にすべて大文字を使用することは主観的ですが、私はそれを避ける傾向があります。

クラスをコピーしたり、スタックベースの POINT のアドレスを に渡したりすると、クラスにあらゆる種類の問題 (二重削除、非ヒープ メモリの削除など) が発生しますsetStruct

単純に値で構成すると、クラスははるかに単純になり、エラーが発生しにくくなります。もう少し多くのデータをコピーすることと引き換えに、ある程度の間接化を節約できますが、メモリを 2 回ヒットする必要がある可能性がある間接化よりも、コピーの方が適切にキャッシュされる可能性があります。

C 構造体との間で明示的に変換する関数getStructと関数を使用しても、実際の問題はありません。setStruct

ただし、ここでの私の質問は次のとおりです。C 構造体が提供しない C++ ラッパーは何を提供しますか? とにかく、クラスで他の操作を行うある種のインターフェースではなく、個々の属性にラップされたメソッドを提供しているだけです。この場合、ラッパーを使用する理由がまったくわかりません (プログラム フローを簡単に追跡できるように、ゲッターとセッターにデバッグ ロジックを追加する予定がない限り)。

于 2013-07-03T17:37:11.657 に答える