I have a class which has a member attribute consisting of an object defined elsewhere. In the code below, A contains a public attribute var which is a B:
class B {
public:
int x, y;
std::vector<int> z;
B(int a, int b, std::vector<int> c) {
x = a; y = b; z = c;
}
};
class A {
public:
B var;
A(int i, int j) {
std::vector<int> someVector;
B(i, j, someVector);
}
};
int main() {
A foo(5, 3);
return 0;
}
This (obviously) doesn't compile as var is instantiated upon an instantiation of A, too late for it to be constructed.
The best way I can do something similar is modify some code:
class B {
public:
int x, y;
std::vector<int> z;
B() {}
void setAttributes(int a, int b, std::vector<int> c) {
x = a; y = b; z = c;
}
};
class A {
public:
B var;
A(int i, int j) {
std::vector<int> someVector;
B.setAttributes(i, j, someVector);
}
};
This does compile because attributes are set after instantiation.
But is there a way to remain closer to the first code snippet?
A(int i, int j) : var(i, j, {}) {}
Also, in your code B(i, j, someVector); does not initialize member variable var, and B.setAttributes(i, j, someVector); wouldn't compile at all.
if you cannot define a useful default constructor and don't want the ugly two step initialization, I guess there is no way around a pointer to B. Something like
#include <memory>
class B {
public:
int x, y;
std::vector<int> z;
B(int a, int b, std::vector<int> c) {
x = a; y = b; z = c;
}
};
class A {
public:
std::unique_ptr<B> var;
A() {
std::vector<int> someVector;
var = std::make_unique<B>(5, 2, someVector);
}
};
int main() {
A foo();
return 0;
}
should do the trick.
I have two object, call the A and B
e.g
class A {
private:
int x;
int y;
public:
A();
A(int x, int y);
void setX(int);
void setY(int);
};
class B {
private:
const A a1;
public:
B();
B(int x, int y) {
//my problem is here
A a(x, y);
this->a1 = a;
};
};
If B is initialised with parameters, I want to have a1 initialised with parameters as well which B is initialised with, hence A(int x, int y).
I don't want a1 initialised in heap.
I currently getting this error
no operator "=" matches these operands -- operand types are: const Brain = Brain
Amend
From the answer below by #songyuanyao
B::B(int x, int y) : a1(x, y){};
it works but I have a different problem now due to my lack of knowledge for const. When I call setX and setY from A(int x, int y) like this
A::A(int x, int y) {
setX(x);
setY(y);
}
void A::setX(int x) {
this->x = x;
}
void A::setY(int y) {
this->y = y;
}
it doesn't seem to change the x and y values/attributes of class A.
You should initialize the const data member with member initializer list. As const object, it could be initialized, but can't be assigned; so this->a1 = a; doesn't work.
For members that cannot be default-initialized, such as members of reference and const-qualified types, member initializers must be specified.
e.g.
B(int x, int y) : a1(x, 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.
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.
I want to use the boost map and the documentation says I need an equality function and a hash function. I think understand what they should do but since I can't find any examples I'm not sure how to do it so I am looking for a trivial example, like a point class with members x, y or something close.
Edit: Finally got it working. Wish I hadn't had to waste so much time for this. Thanks anyway guys.
#include <boost/functional/hash.hpp>
#include <boost/unordered_map.hpp>
#include <boost/foreach.hpp>
#include <iostream>
namespace test { // class whose source i can't edit
class point
{
public:
float x;
float y;
point() : x(0), y(0) {}
point(int x, int y) : x(x), y(y) {}
point(float x, float y) : x(x), y(y) {}
point(double x, double y) : x((float) x), y((float) y) {}
bool operator==(point const& other) const
{
return x == other.x && y == other.y;
}
};
}
namespace test { // my source file
std::size_t hash_value(point const &p) {
boost::hash<int> hasher;
return hasher(p.x) + hasher(p.y);
}
}
int main() {
boost::unordered_map<test::point, std::string> myMap;
test::point p1(1, 2);
myMap[p1] = "1"; //now it works
std::cout << myMap[p1] << std::endl;
return 0;
}
Equality and hash aren't too tough to define. Equality:
class Point {
int x, y;
bool operator==(const Point& p) {
return (x == p.x && y == p.y);
}
};
Hashing tends to involve specializing a function or class.
template<> class boost::hash<Point> {
public:
size_t operator()(const Point& p) {
return boost::hash<int>(p.x) + boost::hash<int>(p.y);
}
};
You may need to read up on the specifics of your hash_map implementation for details, and you may also want to define a different hash algorithm.
This is right from boost documentation...
class point
{
int x;
int y;
public:
point() : x(0), y(0) {}
point(int x, int y) : x(x), y(y) {}
bool operator==(point const& other) const
{
return x == other.x && y == other.y;
}
};
class point
{
...
friend std::size_t hash_value(point const& p)
{
std::size_t seed = 0;
boost::hash_combine(seed, p.x);
boost::hash_combine(seed, p.y);
return seed;
}
...
};