I have a namespace, Vector2, (inside another namespace, CHIM) which represents a 2D Vector. We use the zero vector ( [0, 0] ) multiple times, therefore, we would like to be able to write something like:
Vector2 a = CHIM::Vector2::ZERO;
Which is something commonly used in Unity's game engine.
The problem is, class Vector2 cannot [obviously] contain a member of its type, since it would have infinite size.
We currently solved this by making a static function that returns a Vector2 representing a zero vector. But this makes it such that the code has to run a function:
Vector2 a = CHIM::Vector2::ZERO();
As you can see, it's a bit more verbose, although the result is the same.
Is there any way to make this?
[EDIT]
Here's a simple example of what the code looks like:
#define CHIM_API
namespace CHIM {
union CHIM_API Vector2 {
struct { float x, y; };
struct { float u, v; };
struct { float w, h; };
struct { float width, height; };
float vec[2];
Vector2() : x(0), y(0) {};
Vector2(float x, float y) : x(x), y(y) {}
inline const static Vector2 ZERO = {0, 0}; // ERROR: Variable has incomplete type 'const Vector2'
// Rest of the code
}
Don't inline incomplete data types
namespace CHIM {
union Vector2 {
struct { float x, y; };
struct { float u, v; };
struct { float w, h; };
struct { float width, height; };
float vec[2];
Vector2() : x(0), y(0) {};
Vector2(float x, float y) : x(x), y(y) {}
const static Vector2 ZERO;
};
}
Define const CHIM::Vector2 CHIM::Vector2::ZERO; in .cpp.
See Static Members
However, if the declaration uses constexpr or inline (since C++17) specifier, the member must be declared to have complete type.
With this code:
#include <iostream>
using namespace std;
class point{
public:
double get_x();
void set_x(double v);
double get_y();
void set_y(double z);
private:
double x, y;
};
point operator+(point& p1, point& p2)
{
point sum = {p1.x};// + p2.x, p1.y + p2.y};
return sum;
}
int main()
{
point a = {3.5,2.5}, b = {2.5,4.5}, c;
}
I get the following compiler errors saying the private members cannot be accessed:
point.cpp(22): error C2248: 'point::x': cannot access private member declared in class 'point'
point.cpp(17): note: see declaration of 'point::x'
point.cpp(8): note: see declaration of 'point'
I am pretty new to C++ and can't seem to figure out how to resolve this issue. Any help is much appreciated.
You declared x and y as private so they can't be accessed in that function(or outside the class) unless you make that function a friend of the class, but if you want to overload the + operator, you should do it inside the class, something like this :
class point
{
public:
point(double x, double y) // CONSTRUCTOR
:x(x), y(y)
{
}
double get_x() const{
return x;
};
void set_x(double v)
{
x = v;
};
double get_y() const{
return y;
};
void set_y(double z)
{
y = z;
};
point operator+(const point &obj)
{
double newX = this->x + obj.get_x();
double newY = this->y + obj.get_y();
point sum{newX, newY};
return sum;
};
private:
double x, y;
};
Here, values of x and y is being tried to set through base class constructor.
But, the code is unable to do so.
#include <iostream>
class Point2d {
public:
double x;
double y;
Point2d() : x(0), y(0) {
}
Point2d(double x, double y) : x(x), y(y) {
}
void Show() {
std::cout << "(" << x << "," << y << ")\n";
}
};
class Vector2d : public Point2d {
public:
Vector2d():Point2d(){
}
Vector2d(double x, double y) : Point2d(x,y) {
}
Vector2d(Vector2d const& vec) : Point2d(vec){
}
void Set(double x, double y) {
Point2d::Point2d(x, y);
}
};
int main() {
Vector2d v;
v.Set(20, -39);
v.Show(); // prints '(0,0)' instead of '(20,-39)'
}
My target is to reuse base class constructor, and, overloaded assignment operators as much as possible.
I'm afraid your code won't even compile at
void Set(double x, double y)
{
Point2d::Point2d(x, y);
}
A constructor of a base class should be called at the beginning of the member initializer lists of a subclass constructor, not in a member function.
What you need is probably
class Point2d {
public:
double x;
double y;
Point2d() : x(0), y(0) {
}
Point2d(double x, double y) : x(x), y(y) {
}
void Show() {
std::cout << "(" << x << "," << y << ")\n";
}
Point2d& operator=(Point2d const& rhs)
{
this->x = rhs.x;
this->y = rhs.y;
}
};
class Vector2d : public Point2d {
public:
Vector2d():Point2d(){
}
Vector2d(double x, double y) : Point2d(x,y) {
}
Vector2d(Vector2d const& vec) : Point2d(vec){
}
/* also need to be overloaded in the subclass */
Vector2d& operator=(Vector2d const& rhs)
{
Point2d::operator=(rhs);
return *this;
}
void Set(double x, double y) {
*this = Vector2d(x, y);
}
};
int main() {
Vector2d v;
v.Set(20, -39);
v.Show();
}
Well, you're trying to construct the base class in the setter function, but the base class will already be constructed when the derived class is constructed. I would just set the x and y values of the base class in the setter.
I could find a way to do Designated Initializers in C++0x with only one member initializing.
Is there a way for multiple member initializing ?
public struct Point3D
{
Point3D(float x,y) : X_(x) {}
float X;
};
I want :
public struct Point3D
{
Point3D(float x,y,z) : X_(x), Y_(y), Z_(z) {}
float X_,Y_,Z_;
};
You have a few mistakes in your constructor, here is how you should write it:
/* public */ struct Point3D
// ^^^^^^
// Remove this if you are writing native C++ code!
{
Point3D(float x, float y, float z) : X_(x), Y_(y), Z_(z) {}
// ^^^^^ ^^^^^
// You should specify a type for each argument individually
float X_;
float Y_;
float Z_;
};
Notice, that the public keyword in native C++ has a meaning which is different from the one you probably expect. Just remove that.
Moreover, initialization lists (what you mistakenly call "Designated Initializers") are not a new feature of C++11, they have always been present in C++.
#Andy explained how you should be doing this if you're going to define your own struct.
However, there is an alternative:
#include <tuple>
typedef std::tuple<float, float, float> Point3D;
and then define some function as:
//non-const version
float& x(Point3D & p) { return std::get<0>(p); }
float& y(Point3D & p) { return std::get<1>(p); }
float& z(Point3D & p) { return std::get<2>(p); }
//const-version
float const& x(Point3D const & p) { return std::get<0>(p); }
float const& y(Point3D const & p) { return std::get<1>(p); }
float const& z(Point3D const & p) { return std::get<2>(p); }
Done!
Now you would use it as:
Point3D p {1,2,3};
x(p) = 10; // changing the x component of p!
z(p) = 10; // changing the z component of p!
Means instead of p.x, you write x(p).
Hope that gives you some starting point as to how to reuse existing code.
I use the named constructor idiom to create objects, because I have lots of calls with identical parameters but the object shall be created differently.
The C++ FAQ tell us how to do this. It also tells us how to force objects being heap allocated. Yet it really fails to tell us how to use the named constructor idiom with the new operator.
Because new requires a constructor to be called we cannot directly call named constructors. So I found two workarounds to this problem:
I create an additional copy constructor and hope that optimizing compilers won't create a temporary object.
class point_t {
int X,Y;
point_t(int x, int y) : X(x), Y(y) { }
public:
point_t(const point_t &x) : X(x.X), Y(x.Y) { }
static point_t carthesian(int x, int y) { return point_t(x,y); }
static point_t polar(float radius, float angle) {
return point_t(radius*std::cos(angle), radius*std::sin(angle));
}
void add(int x, int y) { X += x; Y += y; }
};
int main(int argc, char **argv) {
/* XXX: hope that compiler doesn't create a temporary */
point_t *x = new point_t(point_t::carthesian(1,2));
x->add(1,2);
}
The other version is to create separate named constructors. Because function overloading doesn't work on return type I use two different names, which is ugly.
class point_t {
int X,Y;
point_t(int x, int y) : X(x), Y(y) { }
public:
/* XXX: function overloading doesn't work on return types */
static point_t carthesian(int x, int y) { return point_t(x,y); }
static point_t *carthesian_heap(int x, int y) { return new point_t(x,y); }
void add(int x, int y) { X += x; Y += y; }
};
int main(int argc, char **argv) {
point_t *x = point_t::carthesian_heap(1,2);
x->add(1,2);
}
Is there a prettier version that is equal to the example code?
You can avoid named constructor idiom for this completely, and do it using an additonal dummy enum parameter to select the constructor.
enum Carthesian {carthesian};
enum Polar {polar};
class point_t {
int X,Y;
public:
point_t(int x, int y) : X(x), Y(y) { } // may keep as a default
point_t(Carthesian, int x, int y) :X(x),Y(y){}
point_t(Polar, float radius, float angle)
: X (radius*std::cos(angle)), Y(radius*std::sin(angle)) {}
void add(int x, int y) { X += x; Y += y; }
};
int main(int argc, char **argv) {
point_t *x = new point_t(carthesian,1,2);
point_t *y = new point_t(polar,0,3);
x->add(1,2);
}
It is simple, portable, and the only overhead you will see is for the passing of the dummy enum values. In the rare case this overhead is too high for you it can be eliminated by wrapping a function call even when the construction itself is not inlined, as follows:
enum Carthesian {carthesian};
enum Polar {polar};
class point_t {
int X,Y;
void initCarthesian(int x, int y); // may be long, not inlined
void initPolar(float radius, float angle);
public:
point_t(int x, int y) : X(x), Y(y) { } // may keep as a default
point_t(Carthesian, int x, int y)
{initCarthesian(x,y);} // this is short and inlined
point_t(Polar, float radius, float angle) {initPolar(radius, angle);}
void add(int x, int y) { X += x; Y += y; }
};
Another approach is to use a derived class for construction. When using inner classes, it leads into quite a nice syntax I think:
class point_t {
int X,Y;
public:
struct carthesian;
struct polar;
point_t(int x, int y) : X(x), Y(y) { } // may keep as a default
void add(int x, int y) { X += x; Y += y; }
};
struct point_t::carthesian: public point_t
{
carthesian(int x, int y):point_t(x,y){}
};
struct point_t::polar: public point_t
{
polar(float radius, float angle):point_t(radius*std::cos(angle),radius*std::sin(angle)){}
};
int main(int argc, char **argv) {
point_t *x = new point_t::carthesian(1,2);
point_t *y = new point_t::polar(0,3);
x->add(1,2);
return 0;
}
You could write :
point_t *x = new point_t(point_t::carthesian(1,2));
It first calls carthesian() and then the copy-constructor.
Or, is there any problem in it? Perhaps, a bit slow?
By the way, there is one clear advantage in this code: the programmer can clearly see the new operator in his code (where he is using point_t written by someone else), so you can assume that its his responsibility to call delete once he is done with x.
Is this really a problem? In my experience classes tend to be either dynamically allocated most of the time or seldom, if at all. Classes that represent values, such as your point_t class here, belong to the second category, while classes that represent entities (i.e. something with identity) belong to the first one.
So my suggestion is to chose what you think is the best approach for each class and only provide that. Note that you could always return a small directly allocated object which has a private pointer to a larger one, as in the Handle-Body idiom.
On the other hand, other answers show how you may disambiguate among constructors that take arguments of the same number and types. In this line of thought, one alternative approach is to introduce specific types for the arguments as follows:
class radius_t {
float R;
public:
explicit radius_t(float r) : R(r) {}
operator float() const { return R; }
};
class angle_t {
float A;
public:
explicit angle_t(float a) : A(a) {}
operator float() const { return A; }
};
class point_t {
float X,Y;
public:
point_t(float x, float y) : X(x), Y(y) { }
point_t(radius_t radius, angle_t angle) :
X(radius*std::cos(angle)), Y((radius*std::sin(angle)) {
}
void add(int x, int y) { X += x; Y += y; }
};
int main(int argc, char **argv) {
point_t *x = new point_t(radius_t(1),angle_t(2));
x->add(1,2);
}
One approach that I haven't seen is overloading the constructor making the heap allocation use the last argument as an out one (Granted that the second function is not technically a constructor, it doesn't return an instance). The result would be something like (taken as base your second code fragment):
class point_t {
int X,Y;
point_t(int x, int y) : X(x), Y(y) { }
public:
/* XXX: function overloading doesn't work on return types */
static point_t carthesian(const int x, const int y) { return point_t(x,y); }
static void carthesian(const int x, const int y, point_t * & point) { point = new point_t(x,y); }
void add(int x, int y) { X += x; Y += y; }
void add(const point_t & point) { this->X += point.x; this->Y += point.y; }
};
int main(int argc, char **argv) {
point_t p1 = point_t::carthesion(1, 2);
point_t * p2;
point_t::carthesian(1, 2, p2);
p2->add(p1);
}
Can think of template allocator:
template<typename T>
struct Allocator : T
{
template<typename A1, typename A2>
Allocator(A1 a1, A2 a2) : T(a1, a2) {}
};
class point_t {
//...
template<typename T> friend struct Allocator;
};
int main(int argc, char **argv) {
point_t *x = new Allocator<point_t>(1,2);
x->add(1,2);
}
Now Allocator is friend of point_t. So it can access its private constructor. Also, you can add few more constructors like <A1, A2> inside Allocator to make it more generalized. Advantages are:
It doesn't look verbose.
You don't have to worry about compiler optimizations
The friendship is not exploited as, Allocator is a template
and we use it solely for heap allocation
Demo.