Оболочка класса C++ для структуры C


Я хочу написать класс c++, который обертывает структуру c. Вот простой пример для структуры c:

struct POINT {
  long x;
  long y;
}

Теперь я предполагаю, что это следующий класс, но я не уверен, является ли он "performant" или хорошим стилем c++. Я не хотел использовать ненужную переменную или вызов функции. Было бы очень хорошо, если бы вы улучшили мой код :).

Основная идея этого класса заключается в том, что он является всего лишь оболочкой/ обработчиком для структуры. Вот почему setStruct и getStruct могут изменять личные данные прямо и что это просто указатель. Остальные члены всегда называются 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_;
  }
};
}
2 2

2 ответа:

В этом случае вам, возможно, лучше использовать наследование вместо композиции. Это избавит вас от необходимости управлять дополнительным ресурсом и позволит вашей "оболочке" действовать как точка вместо того, чтобы требовать доступов и мутаторов для всей структуры точки.

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). Спасибо Крису за напоминание.

Как уже отмечалось, _POINT является зарезервированным именем, поскольку оно начинается с _ + заглавной буквы.

Использование всех заглавных букв для имен типов субъективно, хотя я склонен избегать этого.

Ваш класс будет иметь всевозможные проблемы (двойное удаление, удаление памяти без кучи и т. д.), Если вы когда-либо скопируете его или передадите адрес стековой точки в setStruct.

Ваш класс будет намного проще и менее подвержен ошибкам, если вы просто составляете по значению. Вы сохраняете уровень косвенное обращение в обмен на копирование немного большего количества данных, но есть вероятность, что копия будет лучше сохранена в кэше, чем косвенное обращение, которое может дважды попасть в память.

Нет никакой реальной проблемы с наличием функций getStruct и setStruct для явного перевода в структуру C и из нее.

Однако вот мой вопрос: Что дает вам ваша оболочка C++, чего не дает C-struct? Вы просто предоставляете обернутые методы отдельным атрибутам в любом случае, а не какой-то вид интерфейс, выполняющий другие операции над классом. В этом случае я вообще не вижу смысла использовать оболочку (если только вы не планируете добавить логику отладки к геттерам и сеттерам, чтобы вам было легче следить за потоком программы).