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.
Related
Class Point is working correctly, It is creating x, y point. Code:
point.h file
#ifndef POINT_H
#define POINT_H
namespace pt
{
class Point
{
int x, y;
public:
Point();
Point(int x, int y);
int getX();
int getY();
};
}
#endif // POINT_H
point.cpp file
#include "point.h"
pt::Point::Point()
{
this->x = this->y = 0;
}
pt::Point::Point(int x, int y)
{
this->x=x;
this->y=y;
}
int pt::Point::getX()
{
return this->x;
}
int pt::Point::getY()
{
return this->y;
}
Meanwhile when I try to create new Point3D class in main that will inherit from Point x, y coordinates and add z to create third dimension, new constructor cant get access to x, y of Point class. Errors are:
1. 'int pt::Point::x' is private at first and second this-> in Point3D constr.
2. Both are 'out of context'
main.cpp
#include <iostream>
#include "point.h"
int main()
{
class Point3D : public pt::Point
{
int z;
public:
getZ()
{
return this->z;
}
Point3D(int x ,int y, int z)
{
this->x=x;
this->y=y;
this->z=z;
}
};
return 0;
}
Thanks for help.
To make x and y accessible to derived classes, you should make them protected:
class Point
{
protected:
int x, y;
public:
Point();
Point(int x, int y);
int getX();
int getY();
};
By default, the visibility of a class member is private (note that this is different from the struct default where a struct member is public by default). On that topic, see this answer.
And as a side note, the idiomatic way to initialize x and y would be to write:
Point3D(int x ,int y, int z) : pt::Point(x,y)
{
this->z=z;
}
Then, you don't need to make x and y protected, they can remain private.
You can even write it like that:
Point3D(int x ,int y, int z) : pt::Point(x,y), z(z)
{}
I am currently rewriting C code into C++ code. While doing that I am replacing structs with classes. That means that some of the variables go from public to private. Now during the transition phase I want to do some error checking by compiling the program sometimes and running it. Thus I intended to have public and private variables at the same time, which are linked, i.e. when I write something into the private variable, the public variable also changes. Nevertheless I only want to write to the private variables by using separate functions, i.e. having the public variables as read-only variables. My current approach is:
#include <iostream>
#include <stdio.h>
class test_vec
{
private:
int x, y;
int data[2];
public:
int x_ext, y_ext;
int data_ext[2];
test_vec(int x, int y)
{
this->x = x;
this->y = y;
this->x_ext = this->x;
this->y_ext = this->y;
}
~test_vec()
{}
void set_x(int x)
{
this->x = x;
}
void set_y(int y)
{
this->y = y;
}
};
int main(void)
{
std::cout << "Hello World\n";
test_vec test(1, 2);
printf("test has the properties (%d, %d)\n", test.x_ext, test.y_ext);//So far, so good
test.set_x(4);
test.set_y(10);
printf("test has the properties (%d, %d)\n", test.x_ext, test.y_ext);//Not updated!
return 0;
}
How can I change the links between the variables? At the moment I already have two pointers copied into each other, but how can I "lock" the external variable onto the internal variable?
Not sure if it's a good design pattern since inline getters are fast but you could create constant references to your private variables:
class test_vec
{
private:
int x, y;
int data[2];
public:
const int &x_ext, &y_ext;
int data_ext[2];
// you have to initialize the references before constructor body
// references cannot be let uninitialized
test_vec(int x, int y) : x_ext(this->x), y_ext(this->y)
{
this->x = x;
this->y = y;
}
~test_vec()
{}
inline void set_x(int x)
{
this->x = x;
}
inline void set_y(int y)
{
this->y = y;
}
};
when x or y changes x_ext and y_ext follow:
Hello World
test has the properties (1, 2)
test has the properties (4, 10)
Bonus: constant references cannot be modified. That's the closest thing of a read property that you got here :)
If you don't want that restriction, just remove the const qualifier, but since you're encouraging encapsuation now that you have C++ I would let it as is and let the writers hit the wall on that (not to mention a good sed/regex replacement could refactor all your writes automatically)
You can use references for these purposes.
Say you have this setup:
class myclass{
public:
myclass(int pa, float pb);
int get_a() const {return a;}
float get_b() const {return b;}
void set_a(int v) {a=v;}
void set_b(float v) {b=v;}
private:
//These are the real values, private
int a;
float b;
public:
//These are the references, public
int& ref_to_a;
float& ref_to_b;
}
myclass::myclass(int pa, float pb)
:a(pa), b(pb), ref_to_a(a), ref_to_b(b)
{
}
You can go like this:
myclass c(33, 12.3f);
c.set_a(12);
c.set_b(111.1f);
//This...
std::cout<<c.ref_to_a<<" "<<c.ref_to_b<<std::endl;
//Should be the same as this...
std::cout<<c.get_a()<<" "<<c.get_b()<<std::endl;
Notice the access settings: the references are public, meaning you can write and read from them. If you want them to be read only you can play with the constness.
I wouldn't bother. Just make the members public for the moment, and when you have fixed all the external references, make them private.
class test_vec
{
public: // For now. Will become private later
int x, y;
public: // For now.
int data[2];
public: // For ever
test_vec(int x, int y)
: x(x), y(y) // Prefer initialization to assignment.
{
}
~test_vec()
{}
void set_x(int x)
{
this->x = x;
}
void set_y(int y)
{
this->y = y;
}
int get_x() const { return x; } // etc
};
If you really wanted to, you could make x_ext be a reference to const - but it's much more idiomatic in C++ to make getters be functions.
class test_vec
{
private:
int x, y;
int data[2];
public:
int const& x_ext;
int const& y_ext;
test_vec(int x_, int y_)
: x(x_), y(y_)
, x_ext(x), y_ext(y) // You *have* to use initialization here.
{
}
~test_vec()
{}
void set_x(int x)
{
this->x = x;
}
void set_y(int y)
{
this->y = y;
}
};
Can anybody help me with the syntax of passing an array of classes
to another class. The syntax of passing an array of classes to another
class has got me beaten. class line tries to be initialised by an
array of points, but the prototype does not match.
#include <iostream>
using namespace std;
class point {
public:
point() {}
point(int x, int y) : X(x), Y(y) {}
void setXY(int x, int y) { X = x; Y = y; }
int getX() { return X; }
int getY() { return Y; }
private:
int X, Y;
};
class line {
public:
line(point *points, int); // Problem line.
private:
point *coords;
int numpoints;
};
int main() {
point points[3];
points[0].setXY(3, 5);
points[1].setXY(7, 9);
points[2].setXY(1, 6);
line l(points, 3); // Problem line.
return 0;
}
Error message:
cygdrive/c/Tmp/cc4mAXRG.o:a.cpp:(.text+0xa7): undefined reference to `line::line(point*, int)'
You need to define a constructor for your line class - you've only provided a declaration.
#include <iostream>
using namespace std;
class point {
public:
point() {}
point(int x, int y) : X(x), Y(y) {}
void setXY(int x, int y) { X = x; Y = y; }
int getX() { return X; }
int getY() { return Y; }
private:
int X, Y;
};
class line {
public:
line(point *points, int count)
: coords(points), numpoints(count) {}
private:
point *coords;
int numpoints;
};
int main() {
point points[3];
points[0].setXY(3, 5);
points[1].setXY(7, 9);
points[2].setXY(1, 6);
line l(points, 3);
return 0;
}
I'd recommend taking a look at the difference between definitions and declarations. Additionally, you should consider maintaining a std::vector<point> in your line class to manage the points. Your line class might then behave as:
#include <vector>
class line {
public:
line(std::vector<point> points)
: coords(points), numpoints(coords.size()) {}
private:
std::vector<point> coords;
int numpoints;
};
You didn't provide a definition for the constructor.
Try:
line(point *points, int np) : coords(points), numpoints(np) {}
Missing body of constructor "line".
You define prototype only.
How to use a single constructor only to create the following objects using C++:
A x;
A y("Hello", 7);
A z(3, "Hello", 2.4);
class A should be having a single constructor to accomodate the creation of objects x, y and z. No change is allowed in the 3 lines specified above.
You cannot(rather should not!) have a single constructor to create all these objects.
You can have constructors which can take different parameters precisely for this reason.
The important question to be asked is:
What exactly are you trying to achieve? What is the need for this?
Perhaps you are trying to solve a problem in wrong way. If you can provide some detail We could help you better.
Yuck!!!!
Anyway, if I was forced to (for example if this, hypothetically speaking, were a homework problem) I would use some sort of variant:
class Variant {
public:
Variant();
Variant( int );
Variant( double );
Variant( const char * );
~Variant();
private:
union data { ... };
enum type { ... };
};
And then use that in my horrid single constructor, along with default arguments to allow empty construction.
A::A( Variant p1 = Variant(), Variant p2 = Variant(), Variant p3 = Variant() );
With c++11:
#include <iostream>
struct A
{
template<typename... Args> A(Args&&... x)
{
std::cout << "construct A\n";
}
};
int main()
{
A x;
A y("Hello", 7);
A z(3, "Hello", 2.4);
return 0;
}
In C++03 you can use initialization funntion:
class A
{
public:
A(int x, const char* y, double z)
{
Init(x, y, z);
}
A(const char* y, int x)
{
Init(x, y);
}
A()
{
Init();
}
private:
void Init(int x = 0, const char* y = 0, double z = 0)
{
}
};
In C++11 you can use constructor delegation:
class A
{
public:
A(int x, const char* y, double z)
{
}
A(const char* y, int x)
: A(x, y, 0)
{
}
A()
: A(0, 0, 0)
{
}
};
Why not just:?
class A {
public:
A(...) { }
};
// test:
int main() {
A x;
A y("Hello", 7);
A z(3, "Hello", 2.4);
}
I just asked this question and the good answers mentioned using an initialization list. So I looked it up in many various places. It was often said that one can use an initialization list to select which constructor to use.
class First
{private:
int a, b, c;
public:
First(int x);
First(int x, int y);
}
First::First(int x, int y, int z = 0)
{ /* this is a constructor that will take two or three int arguements. */ }
First::First(int x, int y = 0, int z = 0)
{ /* and this will be called if one arguement is given */ }
I thought all assignments should be avoided, so how would I write the initializer lists for these two constructors?
I'm not quite sure I follow. As it stands, by providing an argument to x and y (and therefore z), both constructors will be available to call, resulting in ambiguity.
I think what you're looking for is:
class First
{
public:
First(int x);
First(int x, int y, int z = 0);
};
// invoked as First f(1);
First::First(int x) :
a(x), b(0), c(0)
{}
// invoked as First f(1, 2); or First f(1, 2, 3);
First::First(int x, int y, int z) :
a(x), b(y), c(z)
{}
Ctor initialization list isn't for the purpose of choosing which ver of ctor will be chosen.
This is not how things work. If you want to use default arguments, use only one constructof, declare it with default arguments, and define it (without redefining them).
class First
{
private:
int a, b, c;
public:
First(int x, int y = 0, int z = 0);
};
First::First(int x, int y, int z)
{ /*...*/ }
Considering your question, i am not sure you know what an initialisation list is...
I think you mean this:
class First
{
private:
int a, b, c;
public:
First(int x);
First(int x, int y);
}
class Second
{
private:
Second(int x) : First(x) { }
Second(int x, int y) : First(x, y) { }
}
Maybe?