I'm learning C++ and we've been assigned the task of implementing Vector3D classes using Stack and Heap memory. By accident, I've noticed that it is possible to access the protected member fields x, y and z of the Vector3DStack object v being passed into the overload + method.
class Vector3DStack
{
public:
Vector3DStack(double, double, double);
double getMagnitude() const;
double getX() const;
double getY() const;
double getZ() const;
Vector3DStack operator + (Vector3DStack);
Vector3DStack operator - (Vector3DStack);
Vector3DStack operator * (double);
Vector3DStack operator / (double);
Vector3DStack operator % (Vector3DStack);
double operator * (Vector3DStack);
protected:
double x, y, z;
};
Why does C++ allow access to the x, y and z protected fields on the Vector3DStack parameter v when they are declared as protected? I would have expected to have to use v.getX(), v.getY() and v.getZ().
Vector3DStack Vector3DStack::operator + (Vector3DStack v)
{
return Vector3DStack (x + v.x, y + v.y, z + v.z);
}
Many thanks,
George
Because you have implemented operator+ function as member function.
In case of
Vector3DStack operator + (const Vector3DStack& v);
it doesn't really matter - it's adding two objects of Vector3DStack class.
It matters if it comes to
Vector3DStack operator * (double s);
In that case you can only have Vector3DStack as left value, so:
...
vec = vec + 5; // is ok
vec = 5 + vec; // isn't
For the second version you need to implement overloading outside the class:
Vector3DStack operator * (double s, const Vector3DStack& v);
Vector3DStack operator * (const Vector3DStack& v, double s);
in that case operator function won't be able to reach private members of class Vector3DStack.
In this case you could declare operator function as friend - friend functions have access to private members of class.
Additional update: you should pass the object by const reference.
Related
I am getting error in the operator overloading definition. The error goes away if I remove the consts in the parameters. Is there any way I can get it working without removing the consts in the parameters? Also what is happening behind them?
class Vector3D{
public:
float x, y, z;
float dot(Vector3D& v) {
return x * v.x + y * v.y + z * v.z;
}
};
inline float operator *(const Vector3D& a, const Vector3D& b) {
return a.dot(b);
}
You should qualify the member function dot as const as well, otherwise you can't call this member function on a const object:
float dot(Vector3D const& v) const { // <-- const here
You also need to accept v by const& since you are passing it a const object.
You didn't include the error, but it says something like : "cannot call non-const method on const object". Your dot does not modify members and should be declared as const also the argument is not modifed, hence should be const:
class Vector3D{
public:
float x, y, z;
// v---------------- allow to call on const objects
float dot(const Vector3D& v) const {
// ^---------------------------------- pass parameters as const ref
return x * v.x + y * v.y + z * v.z;
}
};
inline float operator *(const Vector3D& a, const Vector3D& b) {
return a.dot(b);
}
In the Vector3D::dot function, neither the object for member function call nor the argument object are modified.
To tell this to the compiler, you should add two consts to your dot definition.
class Vector3D{
public:
float x, y, z;
float dot(const /*(1)*/ Vector3D& v) const /*(2)*/ {
return x * v.x + y * v.y + z * v.z;
}
};
inline float operator *(const Vector3D& a, const Vector3D& b) {
return a.dot(b);
}
(1) : telling that the argument object is not modified
(2) : telling that the object for member function call is not modified
now i am stumbling with c++ code problem.
i made a simple structure 'Vector3' in that i defined the operator+.
and when i use that operator inside const function, it show a red line.
struct Vector3 {
float x, y, z;
Vector3 operator+ (const Vector3 v) {
return Vector3(x + v.x, y + v.y, z + v.z);
};
Vector3(float x, float y, float z) : x(x), y(y), z(z) {};
};
// and i use it inside some const function
struct SomeST {
Vector3 a,b;
Vector3 Function() const
{
return a + b; // error
}
};
and if i delete the const from function, it works!
so it would be amazing if someone can explain what's going on under the hood.
thanks.
Function
Vector3 Function() const
is const. Which means, that this is const inside the function. Which in turn means both a and b are const. a + b syntax is fancy way for writing a.operator + (b) (call operator + method on object a with argument b). Now a is const, so a.operator + method must also be const. Since you've not supplied such operator (the operator you've written is not const) your compiler highlights this as error and if you try to compile it, you will get const based error.
You need to suply operator + (...) const, which in this exact case means you need to add const keyword to definition:
Vector3 operator+ (const Vector3 v) const { ... }
I have the following Point class.
#ifndef POINT_HPP
#define POINT_HPP
#include <string>
class Point {
private:
double m_x, m_y;
public:
Point();
Point(double x, double y);
Point(const Point &p);
~Point();
// selectors
double X() const;
double Y() const;
std::string ToString() const;
double Distance() const;
double Distance(const Point &p) const;
// modifiers
void X(double x);
void Y(double y);
Point operator - () const; // Negate coordinates
//Point operator * (double factor) const; // Scale the coordinates.
Point operator + (const Point & p) const; // Add coordinates.
bool operator == (const Point & p) const; // equally compare
operator.
Point& operator = (const Point& source);
Point& operator *= (double factor);
// non member function to facilitate commutative
multiplication
friend Point operator * (double factor, const Point & p);
friend Point operator * (const Point & p, double factor);
};
Point operator * (double factor, const Point & p) {
return Point(p.m_x * factor, p.m_y * factor);
}
Point operator * (const Point & p, double factor) {
return factor * p;
}
#endif //POINT_HPP
When creating a two Point objects and attempting to perform multiplication with the implemented * operator. I get a multiple definition error. I believe that my * operator is overloaded to so that I can perform double * Point object and Point object * double in any order. Did I declare the friend functions in the incorrect place or provide implementations in the wrong place?
They need to be marked inline if the functions are defined in a header file that will be included from multiple .cpp files. Either that or move the definition (implementation) into a .cpp file. Each .cpp file that includes the header file the way it is now is creating a definition and when they are all linked together, you then have "multiple definitions"
inline Point operator * (double factor, const Point & p) {
return Point(p.m_x * factor, p.m_y * factor);
}
inline Point operator * (const Point & p, double factor) {
return factor * p;
}
It is allowed to define friend functions within the class. Doing so will make them inline.
From CPP reference
A function defined entirely inside a class/struct/union definition, whether it's a member function or a non-member friend function, is implicitly an inline function.
If you do this, you can avoid the multiple definition problem.
I have multiple errors that say either "<snippet of code> needs zero or one argument" or "<snippet of code> needs exactly one argument." For the sake of simplicity I will only post one of these sections of code from my file.h and my file.cc. I don't believe there is anything wrong with my main.cc. Also, the function must be a friend function of the class my_int, so I cannot make it a different type of function or simply use accessor functions. Any help anyone could provide would be most appreciated. Thank you!
file.cc
(friend function of my_int class):
my_int my_int::operator+(const my_int& num1, const my_int& num2) {
my_int temp;
temp = num1 + num2;
return(temp);
}
file.h
(inside a class named my_int)
friend my_int operator+(const my_int& num1, const my_int& num2);
friend my_int operator+(const my_int& num1, const my_int& num2);
means 'declare a free function which takes 2 parameters. Make it a friend so it can see my private members'
my_int my_int::operator+(const my_int& num1, const my_int& num2) {
means 'define the (illegal) member function operator+ which takes total 3 arguments.
EDIT: by request, adding some more info.
There are a number of "correct" ways to implement operators on your classes. The 'best practice' way is to implement all binary operators as free functions (operator+ as a free function is declared with 2 parameters). Operator+ should be implemented where possible in terms of operator+= (a unary operator, therefore define it in the class). It's best practice because it allows you to write overloads of operator+ that take different objects as arguments. For example:
struct X {
explicit X(int val) : _val (val) {}
// getter
int value() const { return _val; }
// this helper += operator eases our journey later on
X& operator+=(int delta) {
_val += delta;
return *this;
}
X& operator+=(const X& r) {
_value += r.value();
return *this;
}
private:
int _val;
}
// implements X + X
X operator+(X l, const X& r)
{
return l += r;
}
// implements X + int
X operator+(X l, int r)
{
return l += r;
}
// implement int + X (returns an X)
X operator+(int l, X r) {
return r += l;
return r;
}
// later, someone else defines a Y and wants it to be addable with X, returning a Z
struct Y {
vector<int> get_numbers() const;
}
struct Z {
Z(vector<int> v);
}
// implement Z = X + Y;
Z operator+(const X& l, const Y& r) {
auto v = r.get_numbers(); // vector<int> instead of auto for c++03
v.push_back(l.value());
return Z { std::move(v) }; // c++11
// return Z(v); // c++03
}
// also implement Z = Y + X
Z operator+(const Y&l , const X&r) {
auto v = l.get_numbers();
v.push_back(r.value());
return Z { std::move(v) };
}
Note that it's possible to declare the free-function forms of binary operators as friends:
struct X {
// this is a free function - not a class memeber, but it can see X::_value
friend X operator+(X, const X&);
private:
int _value;
};
// implementation
X operator+(X l, const X& r) {
l._value += r._value;
return l;
}
but I would argue that this style is less preferable to writing truly unbound free binary operators that are implemented in terms of unary operators (above).
It's also possible to implement binary operators as member functions - in which case they are declared and defined with one parameter (the other being implied as this):
struct X {
X operator+(X r);
private:
int _value;
};
X X::operator+(const X& r) {
// l is implied as *this
return X { _value + r._value };
}
but this is a mistake because while it allows the overload of (X + int), it does not allow overloading (int + X), for which you'd need a free function anyway.
This method:
my_int my_int::operator+(const my_int& num1, const my_int& num2);
is a member function. A member function operator implicitly takes as its left parameter the object pointed to by this (which will be a my_int object). That means that your overload's parameter declaration can't contain more than one object. Change your signature to:
my_int my_int::operator+(const my_int& num2);
Now what was num1 previously is now *this.
The operator + can be used in two kinds of expressions:
unary "plus" expression: +a
binary "plus" expression: a + b
The operator is overloadable for both kinds of expressions. Each overload must be either unary or binary. If the overload is a member function, then the implicit instance argument provides the first operand.
So you have these options:
Free functions:
R operator+(T a) is eligible for +a when a is convertible to T.
S operator+(T lhs, U rhs); is eligble for a + b when a is convertible to T and b to U.
Member functions:
struct Foo
{
R operator+(); // #1
S operator+(T rhs); // #2
} x;
Overload #1 is eligible for +x.
Overload #2 is eligible for x + b when b is convertible to U.
I'm trying to build for android some C++ code, that already working on win32. I have a problem, with overloaded operators. For example:
Code:
Vector2 uv0 = textures.back()->m_uv0;
Vector2 uvt = textures.back()->m_uvt;
uv0 = m_uv0 + Vector2(uv0.x * m_uvt.x, uv0.y * m_uvt.y) + Vector2(0.01f,0.01f);
Where Vector2 is a class declarated above. The declaration of it is:
class Vector2
{
public:
//Constructors
Vector2() : x(0.0f), y(0.0f){}
Vector2(GLfloat _x, GLfloat _y) : x(_x), y(_y) {}
Vector2(double _x, double _y) : x(static_cast<float>(_x)), y(static_cast<float>(_y)) {}
Vector2(int _x, double _y) : x(static_cast<float>(_x)), y(static_cast<float>(_y)) {}
Vector2(double _x, int _y) : x(static_cast<float>(_x)), y(static_cast<float>(_y)) {}
Vector2(int _x, int _y) : x(static_cast<float>(_x)), y(static_cast<float>(_y)) {}
Vector2(GLfloat * pArg) : x(pArg[0]), y(pArg[1]) {}
Vector2(const Vector2 & vector) : x(vector.x), y(vector.y) {}
//Vector's operations
GLfloat Length();
Vector2 & Normalize();
Vector2 operator + (Vector2 & vector);
Vector2 & operator += (Vector2 & vector);
Vector2 operator - ();
Vector2 operator - (Vector2 & vector);
Vector2 & operator -= (Vector2 & vector);
Vector2 operator * (GLfloat k);
Vector2 & operator *= (GLfloat k);
Vector2 operator / (GLfloat k);
Vector2 & operator /= (GLfloat k);
Vector2 & operator = (Vector2 vector);
Vector2 Modulate(Vector2 & vector);
GLfloat Dot(Vector2 & vector);
void Set(GLfloat _x, GLfloat _y);
//access to elements
GLfloat operator [] (unsigned int idx);
//data members
float x;
float y;
};
The definition of this class I won't list here, because it doesn't metter.
But unfortunately I recive an error:
G:/PROJECT266/projects/PROJECT266//jni/../jni/SBE/source/Sprite.cpp: In member function'void Sprite::AddTex(TEX::GUItex)':
G:/PROJECT266/projects/PROJECT266//jni/../jni/SBE/source/Sprite.cpp:103:57: error: no match for 'operator+' in '((Sprite*)this)->Sprite::m_uv0 + Vector2((uv0.Vector2::x *((Sprite*)this)->Sprite::m_uvt.Vector2::x), (uv0.Vector2::y * ((Sprite*)this)->Sprite::m_uvt.Vector2::y))'
G:/PROJECT266/projects/PROJECT266//jni/../jni/SBE/source/Sprite.cpp:103:57: note: candidates are:
G:/PROJECT266/projects/PROJECT266//jni/../jni/SBE/source/SBMath.h:38:10: note: Vector2 Vector2::operator+(Vector2&)
G:/PROJECT266/projects/PROJECT266//jni/../jni/SBE/source/SBMath.h:38:10: note: no known conversion for argument 1 from 'Vector2' to 'Vector2&'
But, if I rewrite the code above like this:
Vector2 uv0 = textures.back()->m_uv0;
Vector2 uvt = textures.back()->m_uvt;
Vector2 vec1 = Vector2(uv0.x * m_uvt.x, uv0.y * m_uvt.y);
Vector2 vec2 = Vector2(0.01f,0.01f);
uv0 = m_uv0 + vec1 + vec2;
There wouldn't be any errors during compilation.
I can't understand, what is the cause of this silly error.
I would be very pleased, if you explain me how to solve this problem.
It is not possible to bind an r-value to a non-const reference.
This line:
uv0 = m_uv0 + Vector2(uv0.x * m_uvt.x, uv0.y * m_uvt.y) + Vector2(0.01f,0.01f);
is equivalent to: (I replaced the parameters with PARAMS to make my example more readable):
uv0 = (m_uv0.operator+(Vector2(PARAMS))).operator+(Vector2(PARAMS));
Here Vector2(PARAMS) will create a temporary object. That is you are trying to pass an r-value reference to your operator overload and the compiler will not find a match as your operator is declared as:
Vector2 operator+ (Vector2& vector);
For more info about why temporaries can't be bound to non-const references see this: How come a non-const reference cannot bind to a temporary object?
In the second example you first declare two Vector2 objects and then pass them to the operator as l-value references which matches your operator overload.
One way to solve the issue and let the operator overload take both l-value and r-value references is to declare it as taking a reference to const as it is perfectly fine to bind an r-value to a reference to const. See the answer by krsteeve for how this can be done.
In general you should always declare functions taking references as taking reference to const if you don't intend to modify the argument.
Examples of reference binding:
Vector2& ref1 = Vector2(); // Error, trying to bind r-value to non-const ref.
Vector2 v;
Vector2& ref2 = v; // OK, v is an l-value reference.
// It is however OK to bind an r-value to a const reference:
const Vector& ref3 = Vector2(); // OK.
You're trying to pass in temporary objects as non-const references. Change the signature of your operator + to take a const references:
Vector2 operator + (const Vector2 & vector);
The reason your second sample works is that you're now naming the Vector2 objects, they're no longer temporary.