Reputation: 107
I want to write an c++ class that wraps a c struct. Here is a simple example for a c struct:
struct POINT {
long x;
long y;
}
Now I am assuming this following class, but I am not sure if it is "performant" nor good c++ style. I didnt want to use a unnecessary variable or function call. It would be very nice if you improve my code :).
The basic idea behind this class is that it is just a wrapper/ handler for the struct. Thats why setStruct
and getStruct
can modify the private data directly and that it is just a pointer. The other members are always named set<Attribute>
and get<Attribute>
.
If you use setStruct
the only disadvantage I can think of is that the struct could be delete due to scopes so that the pointer is "invalid".
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_;
}
};
}
Upvotes: 5
Views: 5912
Reputation: 20063
In this case you may be better off using inheritance instead of composition. It will eliminate the need to manage an additional resource and allow your "wrapper" to act as a POINT instead of requiring accessors and mutators for the entire POINT structure.
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;
}
};
}
If you want to prevent direct access to the members of POINT
you can use private inheritance. You can also provide a conversion operator to allow implicit conversions from Point
to POINT
. This will replace the POINT* getStruct()
member function but still allow you to easily use it with functions that require POINT
as an argument.
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);
}
Note: I have removed the use of inline
as they are unnecessary. Functions defined within a class definition are already inline (see $7.1.2/3). Kudos to Chris for reminding me.
Upvotes: 5
Reputation: 96261
As already noted _POINT
is a reserved name because it starts with _
+ capital letter.
Using all caps for type names is subjective although I tend to steer away from it.
Your class will have all sorts of problems (double delete, delete non-heap memory, and more) if you ever copy it, or pass the address of a stack-based POINT into setStruct
.
Your class will be much much simpler and less prone to error if you simply compose by value. You save a level of indirection in exchange for copying a bit more data, but chances are the copy will be better cached than an indirection that may have to hit memory twice.
There isn't any real problem with having getStruct
and setStruct
functions to translate explicitly to and from the C structure.
However my question here is: What does your C++ wrapper provide you that the C-struct doesn't? You're just providing wrapped methods to the individual attributes anyway rather than some sort of interface that does other operations on the class. In this case I can't actually see a reason to use the wrapper at all (unless you plan to add debugging logic to the getters and setters so you can follow program flow easier).
Upvotes: 0