Operator overload = and const reference - c++

I'm trying to construct a class for colors in C++,
this is not an homework is just that I'm still struggling with references and const.
--Color.h
class Color{
private:
double r;
double g;
double b;
double a;
public:
//constructor, getters and setters...
Color& operator =(Color& other_color); //(1)
}
--Color.cpp
Color& operator=(Color& other_color){
this->r = other_color.get_r(); //line 41
this->b = other_color.get_b();
//and so on...
return *this;
}
like this it works fine but I heard one has to put a const to avoid that by fault the object will be modified by the assignement operation, so one has to declare the other object as const. Like this:
Color& operator =(Color const& other_color); //(2)
but it gives me this errors:
/Users/../color.cpp:41: error: passing 'const Color' as 'this' argument of 'float Color::get_r()' discards qualifiers
so here is my question...
what is happening here? second what would happen if I don't declare other_color as const? what are the possible errors?
PS.: little bonus question:
I want to pass my variable to the opengl glColor4v(colorx.return_rgba()) returning the array [r,g,b,a] of the class Color. This:
float* Color::return_rgba(){
float rgba[4] = {this->r, this->g, this->b, this->a};
return rgba;
}
won't work because rgba won't be in scope anymore after the return so it will be deleted and my pointer will point to not initialized adresses, damn...

passing 'const Color' as 'this' argument of 'float Color::get_r()' discards qualifiers
This means you have to take it further. get_r is probably declared as
float get_r()
and to make it work (const-correctly), you should make it
float get_r() const
second what would happen if I don't declare other_color as const?
You would be unable to assign from const-qualified Colors. You usually want to be able to use const objects, among other as source of assignment. Moreover, it makes the intent not to modify the source clear to the reader of the code.
I want to pass my variable to the opengl glColor4v(colorx.return_rgba()) returning the array [r,g,b,a] of the class Color.
Return a special "vehicle" that would contain the array and convert automatically to float*. Something along
struct ColorQuadruplet
{
float data_[4];
// add initialization and such here
operator float*() { return data_; }
};
ColorQuadruplet Color::get_rgba() const
{
ColorQuadruplet ret;
// fill ret
return ret;
}

You have two choices here. One is for your operator= to directly access to the members of the source object:
Color &operator=(Color const &other) {
r = other.r;
g = other.g;
b = other.b;
a = other.a;
}
The other (which you probably want to do in any case, if you insist on having accessors for the color components at all) is to const-qualify the accessors you've written:
double get_r() const { return r; }
^^^^^
The const here is the part I've added that you apparently don't have.
Edit: as far as passing the values to glColor goes, I'd consider a small front-end something like this:
gl_color(Color const &c) {
glColor4d(c.r, c.g, c.b, c.a);
}

Related

Reference to local variable '...' returned from object initializer

I am trying to overload operators to add PPM images together, creating a new image. However, When trying to make a new object in the function,
PPM& PPM::operator*(const double& rhs) const {
int height = this->getHeight();
int width = this-> getWidth();
int mc = this-> getMaxColorValue();
PPM lhs;
// ...
return lhs;
}
And there's a bunch of other stuff, ending with return(lhs); When I try to compile the code, I get an error saying:
error: reference to local variable 'lhs' returned [-Werror=return-local-addr] PPM lhs;
What is going wrong?
PPM lhs; is local to the function and you cannot return a reference to a local variable.
lhs will die at the end of the function and you will have a dangling reference an if it compile you enter undefined behavior land.
Your operator* is a member function. When called like this:
some_ppm * 1.2
Here, 1.2 is your double rhs.
But what is your lhs?
Looking at your function, the left hand side is not some_ppm. Take a look:
PPM& PPM::operator*(const double& rhs) const {
// ...
PPM lhs;
// ...
return lhs;
}
In this case, lhs is alway a local, new instance of a PPM.
So where is the real rhs?
Rember that when you called an overloaded operator, you effectively call the member function:
some_ppm.operator*(1.2) // actually well formed syntax
And yes you guessed it, it's this. And your operator should not return a reference to the PPM, but should instead do just like a double or an int or even a std::string and return a copy:
//v----- return by value
PPM PPM::operator*(const double& rhs) const {
int height = this->getHeight();
int width = this-> getWidth();
int mc = this-> getMaxColorValue();
PPM result;
// ...
return result;
}

Returning a whole class of information inside a function

so I've been working on a program where I have a class called CDistance, here it is,
class CDistance
{
private:
int feet, inches;
public:
CDistance();
CDistance(int, int);
void setDist();
void printDist() const;
CDistance add(const CDistance&) const;
};
part of what I need to do is to create an array of 5 of these objects, set the feet and inches on each one of them, and then add them together without changing the original variables. This is the function definition, as you can see, it's working with all constant members, so it's a matter of figuring out how to reference the variables, but most importantly, getting them back into a CDistance type to be returned. Should I create a new CDistance type within this function to work with the ref
CDistance CDistance::add(const CDistance&) const
{
}
That's where I've been stuck, I'm kind of confused about the whole pointers and encapsulation deal. I'm new to programming, and have learned that the hard way, but if someone could help me out with this, I would really appreciate it
Should I create a new CDistance type within this function to work with the ref
Yes, you'll need a new object to modify and return:
CDistance add(const CDistance& other) const {
CDistance result = *this; // Copy this object
result.feet += other.feet; // Add the other object...
result.inches += other.inches; // ... to the copy
return result; // Return the copy
}
Note that this isn't complete; there's one deliberate error, and an unknown number of accidental errors, which you'll need to fix yourself.
You can simply return a local result instance from your function:
CDistance CDistance::add(const CDistance& other) const
{
CDistance result(*this);
// Calculate the result using result.feet, result.inches and
// other.feet, other.inches
return result;
}

Const mismatches: 2 overloads have no legal conversion for 'this' pointer

I'm getting this weird error:
error C2663:
'sf::Drawable::SetPosition' : 2
overloads have no legal conversion for
'this' pointer
I think it has something to do with const mismatches but I don't know where, or why.
In the following code I have a vector of shapes and sprites, and when trying to access one of the vectors shapes and calling one of its functions I'm getting the error.
std::vector<sf::Shape> Shapes;
std::vector<sf::Sprite> Sprites;
bool AddShape(sf::Shape& S){
Shapes.push_back(S); return true;
};
bool AddSprite(sf::Sprite& S){
Sprites.push_back(S); return true;
};
private:
virtual void Render(sf::RenderTarget& target) const {
for(unsigned short I; I<Shapes.size(); I++){
Shapes[I].SetPosition(
Shapes[I].GetPosition().x + GetPosition().x,
Shapes[I].GetPosition().y + GetPosition().y);
target.Draw(Shapes[I]);
}
for(unsigned short I; I<Sprites.size(); I++){
target.Draw(Sprites[I]);
}
}
How can I fix this?
Render is declared with a const after the parameters. This means it does not change its object. Which means, that all of the object's member variables are considered constants within Render, as changing their state means changing the containing object. Assuming Shapes is a member variable, and that SetPosition does change the shape (i.e. not declared as const), you cannot call it within a const member function.
So, remove the const from Render and you'll be fine (you fix your logic, in case it must be const).

What to do with proxy class copy-assignment operator?

Consider the following proxy class:
class VertexProxy
{
public:
VertexProxy(double* x, double* y, double* z)
: x_(x), y_(y), z_(z) {}
VertexProxy(const VertexProxy& rhs)
: x_(rhs.x_), y_(rhs.y_), z_(rhs.z_) {}
// Coordinate getters
double x() const {return *x_;}
double y() const {return *y_;}
double z() const {return *z_;}
// Coordinate setters
VertexProxy& x(double val) {*x_ = val; return *this;}
VertexProxy& y(double val) {*y_ = val; return *this;}
VertexProxy& z(double val) {*z_ = val; return *this;}
VertexProxy& operator=(const VertexProxy& rhs)
{
// Should it be this
x_ = rhs.x_; y_ = rhs.y_; z_ = rhs.z_;
// or this?
*x_ = *rhs.x_; *y_ = *rhs.y_; *z_ = *rhs.z_;
return *this;
}
private:
double* x_; double* y_; double* z_;
};
I need to be able to reset the proxy so that it holds different coordinate pointers (similarly to boost::shared_ptr.reset(). In addition, I would like to be able to assign the coordinate values to the ones from a different proxy ( i.e. proxy1.assign(proxy2) ).
What should be the meaning of operator= in my class above? To copy rhs's pointers (shallow copy) or rhs's values? Or should I just make operator= private and provide two members functions to avoid the ambiguity of operator=?
EDIT:
Ok, here's some background information. I'm writing a wrapper around a 3rd party GIS library (shapelib), which stores vertex coordinates (x,y,z,m) in separate arrays (instead of an array of structs). My proxy class is used to make this struct of arrays appear more like an array of structs. It works in tandem with a custom vertex iterator class that makes it much easier to work with ranges of vertices.
Shapelib handles the memory management. All my proxy class does is present a different "view" into the vertex data. When the user manipulates vertex coordinates using my proxy, it actually manipulates the vertex coordinates in the shapelib shape object.
Given that your copy constructor copies the pointers, for consistency your copy-assignment operator should assign the pointers.
VertexProxy& operator=(const VertexProxy& rhs)
{
x_ = rhs.x_;
y_ = rhs.y_;
z_ = rhs.z_;
return *this;
}
It would be very inconsistent if this (admittedly questionable) code:
VertexProxy test( const VertexProxy& other )
{
double tmp1, tmp2, tmp3;
VertexProxy p1( &tmp1, &tmp2, &tmp3 );
p1 = other;
return p1;
}
acted differently to:
VertexProxy test( const VertexProxy& other )
{
double tmp1, tmp2, tmp3; // unused
VertexProxy p1( other );
return p1;
}
It's pretty simple. Do you want VertexProxy to act like a pointer, or a value? If you'd rather it acted like a pointer, then copy the pointers, if you'd rather it acted like a value, copy the values. Nobody can tell you that your class is a pointer or a value (especially since you seem to have something somewhat unusual). If you want better advice, we'd need to know what holds the actual doubles and why.
Quick edit:
Seems to me like actually, if you did the dereference, you'd have it acting like a reference or a pointer. However, the original point remains the same.
std::bitset::reference performs a role similar to my VertexProxy and can be used as a model.
typedef std::bitset<8> Bitset;
Bitset bset1, bset2;
Bitset::reference r1(bset1[3]);
Bitset::reference r2(bset2[3]);
r1 = 1;
r2 = r1;
std::cout << "bset2 = " << bset2 << "\n";
r2 = r1 above copies values.
I would say that it depends on how large the object is.
If the proxy subject is very big then using a reference counting shared pointer is the way to go. Just copy the shared pointer in the copy operation.
If it isn't that big then a deep copy is better. Less hassle all around for everyone.

C++ types and functions

I'm having some trouble compiling my code - it has to do with the types I'm passing in. Here is what the compiler says:
R3Mesh.cpp: In copy constructor 'R3Mesh::R3Mesh(const R3Mesh&)':
R3Mesh.cpp:79: error: no matching function for call to 'R3Mesh::CreateHalfEdge(R3MeshVertex*&, R3MeshFace*&, R3MeshHalfEdge*&, R3MeshHalfEdge*&)'
R3Mesh.h:178: note: candidates are: R3MeshHalfEdge* R3Mesh::CreateHalfEdge(const R3MeshVertex*&, const R3MeshFace*&, const R3MeshHalfEdge*&, const R3MeshHalfEdge*&)
R3Mesh.cpp: In constructor 'R3MeshHalfEdge::R3MeshHalfEdge(const R3MeshVertex*&, const R3MeshFace*&, const R3MeshHalfEdge*&, const R3MeshHalfEdge*&)':
R3Mesh.cpp:1477: error: invalid conversion from 'const R3MeshVertex*' to 'R3MeshVertex*'
R3Mesh.cpp:1477: error: invalid conversion from 'const R3MeshFace*' to 'R3MeshFace*'
R3Mesh.cpp:1477: error: invalid conversion from 'const R3MeshHalfEdge*' to 'R3MeshHalfEdge*'
R3Mesh.cpp:1477: error: invalid conversion from 'const R3MeshHalfEdge*' to 'R3MeshHalfEdge*'
Here is how I define my R3MeshHalfEdge:
struct R3MeshHalfEdge {
// Constructors
R3MeshHalfEdge(void);
R3MeshHalfEdge(const R3MeshHalfEdge& half_edge);
R3MeshHalfEdge(const R3MeshVertex*& vertex, const R3MeshFace*& face,
const R3MeshHalfEdge*& opposite, const R3MeshHalfEdge*& next);
R3MeshVertex *vertex;
R3MeshFace *face;
R3MeshHalfEdge *opposite;
R3MeshHalfEdge *next;
int id;
};
This is what the first error complains about:
R3MeshHalfEdge *R3Mesh::
CreateHalfEdge(const R3MeshVertex*& vertex, const R3MeshFace*& face,
const R3MeshHalfEdge*& opposite, const R3MeshHalfEdge*& next)
{
// Create half_edge
R3MeshHalfEdge *half_edge = new R3MeshHalfEdge(vertex, face, opposite, next);
// Set half_edge ID
half_edge->id = half_edges.size();
// Add to list
half_edges.push_back(half_edge);
// Return half_edge
return half_edge;
}
This is what the second error complains about:
R3MeshHalfEdge::
R3MeshHalfEdge(const R3MeshVertex*& vertex, const R3MeshFace*& face,
const R3MeshHalfEdge*& opposite, const R3MeshHalfEdge*& next)
: vertex(vertex),
face(face),
opposite(opposite),
next(next),
id(0)
{
}
Here is where I call the CreateHalfEdge function:
for(int i=0; i<mesh.NFaces(); i++)
{
R3MeshFace *f = mesh.Face(i);
vector<R3MeshVertex *> face_vertices; // assume vertices are stored in order around the perimeter of the face
for(unsigned int j = 0; j<f->vertices.size(); j++)
{
R3MeshVertex *v1 = f->vertices[j];
R3MeshVertex *v2;
if(j==f->vertices.size()-1)
v2 = f->vertices[0];
else
v2 = f->vertices[j+1];
int v1_id = v1->id;
int v2_id = v2->id;
R3MeshHalfEdge *next = NULL;
R3MeshHalfEdge *opposite = NULL;
R3MeshHalfEdge *half_edge = CreateHalfEdge(v1, f, opposite, next);
}
... }
The constructor is wrong:
R3MeshHalfEdge(const R3MeshVertex*& vertex, const R3MeshFace*& face,
const R3MeshHalfEdge*& opposite, const R3MeshHalfEdge*& next);
You pass pointers to const and assign them to pointers to non-const, which fails.
Correct it like so:
R3MeshHalfEdge(R3MeshVertex* vertex, R3MeshFace* face,
R3MeshHalfEdge* opposite, R3MeshHalfEdge* next);
As a remark:
there are two level of const with pointers: pointers to const (const X*) and const pointers (X* const) the former can point to something else but cannot change the object pointed to while the latter cannot be rebound to another object but can change the object pointed. You can combine them to have a const pointer to const (const X* const)
don't pass pointers by reference (*&) unless you intend to modify the pointer itself, and not the object pointed.
Saying const type *&parameter means that you can modify parameter:
void foo(const int *&parameter)
{
int bar= 0;
parameter= &bar;
}
I suspect you don't want to do that. Instead of passing pointers by reference, either pass them by value (since you aren't modifying them) or pass them by const reference (const type * const &parameter).
You're passing non-const pointers to a function that expects const pointer arguments, it seems.
Note:
...But this shouldn't be a problem. I suspect there's something else going on here, but the question is missing some information. The compiler error is about something in the copy constructor R3Mesh::R3Mesh(const R3Mesh&), which isn't shown in the question.
Edit: OK, it is shown now. I would suggest clearing up the const reference to pointer issues first, and seeing what's left.
The second error is pretty clear, actually - either the arguments to the R3MeshHalfEdge constructor shouldn't be references to const pointers (which tell the compiler you don't intend to change the objects they point to) or the data members you assign those arguments to should be const pointers themselves.
You need to look at your argument and reevaluate what should be constant and what shouldn't.
Your compiler error is thrown because you are pointing a nonconstant pointer (vertex, for example) at constant memory (the vertex argument). In C++ constant and nonconstant variables are different types.
Read through this for a lot more detail.
If you just want it to work, remove all your consts and it will compile. If you want your arguments to be constant, you'll have to do copy copying and assignments of data (not pointers!) to remove the error.
Also, rename your arguments so that you don't have name collisions with your member variables.