How should I declare this operator overload? - c++

I need to multiply a const Vector by an int, but I have to declare the overload as a non-member function and not as a method or it will not compile; how would I write the overload as a method?
namespace N
{
class Vector {
public:
double x, y, z;
Vector( );
Vector(double x, double y = 0, double z = 0);
Vector operator*(double k);
//friend Vector operator*(const Vector u, double k);
};
}
namespace N
{
Vector::Vector( )
{
x = 0;
y = 0;
z = 0;
}
// Creates a vector with initial Cartesian components.
//
Vector::Vector(double x, double y, double z) :
x(x),
y(y),
z(z)
{
}
// Allows multiplying a vector by a scalar.
//
Vector Vector::operator*(double k)
{
Vector scaled;
scaled.x = x * k;
scaled.y = y * k;
scaled.z = z * k;
return scaled;
}
// Allows multiplying a vector by a scalar.
//
/*Vector operator*(const Vector u, double k)
{
return Vector(u.x * k, u.y * k, u.z * k);
}*/
}
const N::Vector A(3, 4);
const N::Vector B(4, 3);
int main( )
{
N::Vector resulting = A * 3;
return 0;
}

As a member, simply change the code to
Vector operator*(double k) const;
and in the definition
Vector Vector::operator*(double k) const ...
As top-level:
friend Vector operator*(const Vector& u, double k);
and
Vector operator*(const Vector& u, double k)
{
return Vector(u.x * k, u.y * k, u.z * k);
}

Related

Multiplication operator not returning value

I have a Matrix3 class which has an overloaded * operator so i should be able to go:
Matrix3 m1, m2, m3
m2.setRotateX(3.98f); //values are not important just setting a value.
m3.setRotateZ(9.62f);
m1 = m2 * m3
Expected result:
m1 is assigned the result of m2 * m3 calculation. Instead it appears to be still assigned whatever was in memory when it was created.
I have looked at it in the debugger and the result code at the end of the operator * method is assigned to the correct values but it never is assigned for some reason.
I am running Visual Studio 2017 (I tried updating to latest version) and currently running with the Debug x86 profile.
I should also point out I am not using a pre-made maths library because this is part of an assignment.
Here is the full code for the class:
matrix3.h
#pragma once
#include "vector3.h"
class Matrix3
{
public:
union
{
struct
{
Vector3 xAxis;
Vector3 yAxis;
union {
Vector3 zAxis;
Vector3 translation;
};
};
Vector3 axis[3];
float data[3][3];
};
static const Matrix3 identity;
Matrix3(Vector3 x, Vector3 y, Vector3 z) : xAxis{ x }, yAxis{ y }, zAxis{ z } { }
Matrix3(float f1, float f2, float f3, float f4, float f5, float f6, float f7, float f8, float f9) : data{ f1, f2, f3, f4, f5, f6, f7, f8, f9 } {}
Matrix3() : Matrix3{ identity } {}
Matrix3(const Matrix3 &other)
{
for (int i = 0; i > 3; i++)
axis[i] = other.axis[i];
}
Matrix3& operator= (const Matrix3& other);
Vector3& operator[] (int index);
const Vector3& operator[] (int index) const;
Matrix3 operator * (const Matrix3& other) const;
Vector3 operator * (const Vector3& v) const;
Matrix3 operator + (const Matrix3& other) const;
Matrix3 operator - (const Matrix3& other) const;
operator float*() { return reinterpret_cast<float*>(data); }
Matrix3 transpose() const;
void setScaled(float x, float y, float z);
void setScaled(const Vector3& v);
void scale(float x, float y, float z);
void scale(const Vector3 v);
void setRotateX(float radians);
void setRotateY(float radians);
void setRotateZ(float radians);
void rotateX(float radians);
void rotateY(float radians);
void rotateZ(float radians);
void setEuler(float pitch, float yaw, float roll);
operator std::string() const;
friend std::ostream& operator<< (std::ostream& os, const Matrix3& matrix);
};
matrix3.cpp
#include "Matrix3.h"
const Matrix3 Matrix3::identity = Matrix3({ 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 });
static const int MATRIX_DIMS = 3;
Vector3& Matrix3::operator[] (int index)
{
return axis[index];
}
const Vector3& Matrix3::operator[] (int index) const
{
return axis[index];
}
Matrix3& Matrix3::operator=(const Matrix3& other)
{
xAxis = other.xAxis;
yAxis = other.yAxis;
zAxis = other.zAxis;
return *this;
}
Matrix3 Matrix3::operator * (const Matrix3& other) const
{
Matrix3 result;
for (int r = 0; r < 3; r++)
for (int c = 0; c < 3; c++)
result.data[c][r] = data[0][r] * other.data[c][0] +
data[1][r] * other.data[c][1] +
data[2][r] * other.data[c][2];
return result;
}
Vector3 Matrix3::operator * (const Vector3& v) const
{
Vector3 result;
for (int r = 0; r < 3; ++r)
{
result[r] = 0;
for (int i = 0; i < MATRIX_DIMS; ++i)
result[r] += data[i][r] * v[i];
}
return result;
}
Matrix3 Matrix3::operator+(const Matrix3& other) const
{
Matrix3 result;
for (int x = 0; x < MATRIX_DIMS; x++)
for (int y = 0; y < MATRIX_DIMS; y++)
result[x][y] = data[x][y] + other[x][y];
return result;
}
Matrix3 Matrix3::operator-(const Matrix3& other) const
{
Matrix3 result;
for (int x = 0; x < MATRIX_DIMS; x++)
for (int y = 0; y < MATRIX_DIMS; y++)
result[x][y] = data[x][y] - other[x][y];
return result;
}
Matrix3 Matrix3::transpose() const
{
Matrix3 result;
for (int r = 0; r < MATRIX_DIMS; ++r)
for (int c = 0; c < MATRIX_DIMS; ++c)
result.data[r][c] = data[c][r];
return result;
}
void Matrix3::setScaled(const Vector3& v)
{
// set scale of each axis
xAxis = { v.x, 0, 0 };
yAxis = { 0, v.y, 0 };
zAxis = { 0, 0, v.z };
}
void Matrix3::setScaled(float x, float y, float z)
{
// set scale of each axis
xAxis = { x, 0, 0 };
yAxis = { 0, y, 0 };
zAxis = { 0, 0, z };
}
void Matrix3::scale(const Vector3 v)
{
Matrix3 m;
m.setScaled(v.x, v.y, v.z);
*this = *this * m;
}
void Matrix3::scale(float x, float y, float z)
{
Matrix3 m;
m.setScaled(x, y, z);
*this = *this * m;
}
void Matrix3::rotateX(float radians)
{
Matrix3 m;
m.setRotateX(radians);
*this = *this * m;
}
void Matrix3::rotateY(float radians)
{
Matrix3 m;
m.setRotateY(radians);
*this = *this * m;
}
void Matrix3::rotateZ(float radians)
{
Matrix3 m;
m.setRotateZ(radians);
*this = *this * m;
}
void Matrix3::setRotateX(float radians)
{
xAxis = { 1, 0, 0 };
yAxis = { 0, cosf(radians), sinf(radians) };
zAxis = { 0, -sinf(radians), cosf(radians) };
}
void Matrix3::setRotateY(float radians)
{
xAxis = { cosf(radians), 0, -sinf(radians) };
yAxis = { 0, 1, 0 };
zAxis = { sinf(radians), 0, cosf(radians) };
}
void Matrix3::setRotateZ(float radians)
{
xAxis = { cosf(radians), sinf(radians), 0 };
yAxis = { -sinf(radians), cosf(radians), 0 };
zAxis = { 0, 0, 1 };
}
void Matrix3::setEuler(float pitch, float yaw, float roll)
{
Matrix3 x, y, z;
x.setRotateX(pitch);
y.setRotateY(yaw);
z.setRotateZ(roll);
*this = z * y * x;
}
Matrix3::operator std::string() const
{
std::string result = "";
for (int r = 0; r < MATRIX_DIMS; ++r)
{
result += "{";
for (int c = 0; c < MATRIX_DIMS; ++c)
{
result += std::to_string(data[r][c]);
if (r != MATRIX_DIMS - 1 || c != MATRIX_DIMS - 1)
result += ",";
}
result += "}";
}
return result;
}
std::ostream& operator<< (std::ostream& os, const Matrix3& matrix)
{
os << static_cast<std::string>(matrix);
return os;
}
The supplied code exhibits undefined behavior. In c++ only up to one member of a union is active at any time. Only a union's active member can be read from. Assigning to a union member makes it active and makes all other members inactive. For example, if you assign a value to identity.data it's undefined behavior to try to read from identity.axis until you assign a value to identity.axis, after which you can no longer read from identity.data. This is different from how it works in c.
By calling void Matrix3::setRotateX(float radians) you assign values to the union's xAxis, yAxis and zAxis members, making the struct component of the union active. Then, when you multiply m2 with m3 you call Matrix3 Matrix3::operator * (const Matrix3& other) const which reads from the union's data member which is not active, which leads to undefined behavior.
The easiest solution would likely to be to dispose of the union all together and use only one of the representations.

How to make inherited class different from parent only by one value in C++?

I'm trying to write a class for the UnitVector, having already written the one for a generic Vector. The UnitVector class diverges from the Vector class only by the fact that the abs variable is set to 1.0f. I'd like to know what the best approach to the problem would be, whether it's better to make another class, UnitVector, that inherits the Vector class (my current idea, that's giving me problems) or to just write a method in the Vector class
Here's my code for the class Vector:
Vector.h
class Vector
{
public:
Vector();
Vector(float x, float y);
void set_by_angle(float abs, float angle);
void set(float x, float y);
void rotate(float angle);
void scale(float scale_factor);
void translate(float x, float y);
void translate(Vector v);
float get_abs();
float get_angle();
static Vector create_by_angle(float abs, float angle);
static Vector create(float x, float y);
static Vector create_from_vectors(Vector v1, Vector v2, float abs);
static float get_distance(Vector v1, Vector v2);
static float get_angle(float x, float y);
static float get_angle(Vector v);
void to_string();
Vector operator=(const Vector &v);
bool operator==(const Vector &v);
bool operator!=(const Vector &v);
Vector operator+=(const Vector &v);
friend Vector operator+(const Vector &v1, const Vector &v2);
friend Vector operator-(const Vector &v1, const Vector &v2);
float x;
float y;
private:
float abs;
float angle;
};
Vector.cpp
#define _USE_MATH_DEFINES
#include <math.h>
#include <iostream>
#include <string>
#include "vector.h"
using namespace std;
Vector::Vector() : Vector(0, 0) {}
Vector::Vector(float x, float y)
{
set(x, y);
}
void Vector::set_by_angle(float abs, float angle)
{
this->abs = abs;
this->angle = angle;
x = abs * cos(angle);
y = abs * sin(angle);
}
void Vector::set(float x, float y)
{
this->x = x;
this->y = y;
abs = get_abs();
angle = get_angle();
}
void Vector::rotate(float angle)
{
set_by_angle(this->abs, this->angle + angle);
}
void Vector::scale(float scale_factor)
{
set(x * scale_factor, y * scale_factor);
}
void Vector::translate(float x, float y)
{
set(this->x + x, this->y + y);
}
void Vector::translate(Vector v)
{
translate(v.x, v.y);
}
float Vector::get_abs()
{
return sqrt(pow(x, 2) + pow(y, 2));
}
float Vector::get_angle()
{
return get_angle(x, y);
}
Vector Vector::create_by_angle(float abs, float angle)
{
Vector v;
v.set_by_angle(abs, angle);
return v;
}
Vector Vector::create(float x, float y)
{
Vector v;
v.set(x, y);
return v;
}
float Vector::get_distance(Vector v1, Vector v2)
{
return sqrt(pow(v1.x - v2.x, 2) + pow(v1.y - v2.y, 2));
}
Vector Vector::create_from_vectors(Vector v1, Vector v2, float abs)
{
float x = v2.x - v1.x;
float y = v2.y - v1.y;
Vector v;
v.set_by_angle(abs, Vector(x, y).get_angle());
return v;
}
float Vector::get_angle(float x, float y)
{
float tan = 0.0f;
float angle = 0.0f;
if (x != 0)
{
tan = y / x;
angle = atan(tan);
// this setting applies to the graphic reference system
if (x > 0 && y < 0) angle = 2 * M_PI + angle;
if (x < 0 && y > 0) angle += M_PI;
if (x < 0 && y < 0) angle += M_PI;
}
if (x == 0)
{
if (y > 0) angle = M_PI_2;
if (y < 0) angle = 3 * M_PI_2;
}
if (y == 0)
{
if (x > 0) angle = 0.0f;
if (x < 0) angle = M_PI;
}
return angle;
}
float Vector::get_angle(Vector v)
{
return get_angle(v.x, v.y);
}
void Vector::to_string()
{
cout << "x: " + std::to_string(x) + " y: " + std::to_string(y) << endl;
}
Vector operator+(const Vector &v1, const Vector &v2)
{
Vector tmp;
tmp.set(v1.x + v2.x, v1.y + v2.y);
return tmp;
}
Vector operator-(const Vector &v1, const Vector &v2)
{
return v1 + Vector(-v2.x, -v2.y);
}
Vector Vector::operator+=(const Vector &v)
{
set(x + v.x, y + v.y);
return *this;
}
Vector Vector::operator=(const Vector &v)
{
set(v.x, v.y);
return *this;
}
bool Vector::operator==(const Vector &v)
{
return
(
(x == v.x)
&&
(y == v.y)
);
}
bool Vector::operator!=(const Vector &v)
{
return !(*this == v);
}
Thanks in advance!
Just add the following two methods:
void normalize()
{
float scalar = 1.0 / this->get_abs();
this->x *= scalar;
this->y *= scalar;
}
And:
static Vector get_unit(const Vector &v)
{
float scalar = 1.0 / v.get_abs();
return Vector(v.x * scalar, v.y * scalar);
}

Error: object of abstract class "Sphere" not allowed. and Error: no operator "=" matches these operands

I've been trying to resolve a error for the last day or so and can't seem to work it through.
It's the kind of error that the fix is probably very easy :S
I tried to search for similar questions but the fixes don't apply.
main.c
int main(int argc, char *argv[]){
int width, height;
std::vector<Obj*> world;
world.push_back(new Sphere(Vec(0, 0, -22), 2, Vec(0.2, 0.2, 0.2), true));
(...)
return 0;
}
The error is found when I try to create a Sphere.
Relevant classes
Obj.h
class Obj
{
public:
Vec color;
bool culling;
virtual bool intersect(const Vec &ray_orig, Vec &ray_dir, float *t0 = NULL, float *t1 = NULL) = 0;
};
Sphere.h
class Sphere: public Obj
{
public:
Vec center;
float radius, radius2;
Sphere(Vec center, float radius, Vec color, bool culling);
bool intersect(const Vec &ray_orig, Vec &ray_dir, float *t0 = NULL, float *t1 = NULL);
};
Sphere.c
Sphere::Sphere(Vec center, float radius, Vec color, bool culling){
this->center = center;
this->radius = radius;
this->color = color;
this->culling = culling;
}
bool Sphere::intersect(const Vec &ray_orig, Vec &ray_dir, float *t0 = NULL, float *t1 = NULL) {...}
These second error appears when I do this->color = color;. Not sure if they are related.
Vec is a simple struct with 3 variables.
If you need more information I'll add as soon as possible.
Thank you in advance.
Jose
EDIT
Sorry for the delay.
intersect(...) is the only function in the obj class. Is there anyway to maintain the abstraction since there are several objects(sphere,box,...).
As requested here goes the definition of vec.h
vec.h
struct Vec {
float x, y, z;
Vec() {x = 0, y = 0, z = 0;}
Vec(float val) {x = val, y = val, z = val;}
Vec(float x_val,float y_val,float z_val) {x = x_val, y = y_val, z = z_val;}
Vec(const Vec& copy) : x(copy.x), y(copy.y), z(copy.z) { }
Vec operator+ (const Vec& p) const {
return Vec(x + p.x, y + p.y, z + p.z);
}
Vec operator- (const Vec& p) const {
return Vec(x - p.x, y - p.y, z - p.z);
}
Vec& operator += (const Vec& p) {
x += p.x; y += p.y; z += p.z;
return *this;
}
Vec& operator -= (const Vec& p) {
x -= p.x; y -= p.y; z -= p.z;
return *this;
}
Vec operator* (const float f) const {
return Vec(f * x, f * y, f * z);
}
Vec& operator*= (const float f) {
x *= f; y *= f; z *= f;
return *this;
}
Vec operator/ (const float f) const {
float inv = 1.f / f;
return Vec(inv * x, inv * y, inv * z);
}
Vec& operator/= (const float f) {
float inv = 1.f / f;
x *= inv; y *= inv; z *= inv;
return *this;
}
Vec& operator= (const Vec& p) {
x = p.x; y = p.y; z = p.z;
return *this;
}
bool operator== (const Vec& p) {
if(x == p.x && y == p.y && z == p.z)
return true;
return false;
}
float length_squared() const {
return x*x + y*y + z*z;
}
float length() const {
return sqrt(length_squared());
}
Vec norm() const {
float nor = x * x + y * y + z * z;
if (nor > 0) {
float invNor = 1 / sqrt(nor);
(float)x *= invNor, (float)y *= invNor, (float)z *= invNor;
}
return *this;
}
Vec cross(const Vec&b) {
return Vec(y*b.z-z*b.y,z*b.x-x*b.z,x*b.y-y*b.x);
}
float dot(const Vec& v) {
return x * v.x + y * v.y + z * v.z;
}
};
It seems the problem was indeed in the vec file.
Can't find a reasoning about the fix, but changing the Vec struct to a class fixed all the problems.
Thanks for the help.

C++ overloading an operator double * Vec

I'm trying to make a Vec class to represent a set of 3 doubles, x, y, z, respectively. What I would like to do is make it so that I can multiply a scalar times the vector and have it multiply each component.
I have been able to get it to work when I mutliply a vector by a scalar, but not when I do the reverse. For example, the following works:
Vec a = Vec(1.0, 1.0, 1.0);
Vec b = a * 2.0;
But, whenever I try to multiply a scalar by a vector, it doesn't work. Ideally the command would look like this:
Vec a = Vec(1.0, 1.0, 1.0);
Vec b = 2.0 * a;
Here is the code I've done so far:
#include "Vec.h"
#include <limits>
#include <cmath>
#include "constants.h"
#include <iostream>
#include <string>
double Vec::angle( const Vec & vec) {
return acos((this->dot(vec))/(this->mag() * mag()));
}
double Vec::angle_d(const Vec & vec) {
return (angle(vec) * _PI / 180.0);
}
double Vec::angle_r(const Vec & vec) {
return this->angle(vec);
}
Vec Vec::cross( const Vec& vec) {
return Vec( (y * vec.z - z * vec.y),
(z * vec.x - x * vec.z),
(x * vec.y - y * vec.x));
}
double Vec::dot( const Vec & vec) {
return (x * vec.x + y * vec.y + z * vec.z);
}
double Vec::mag() {
return std::sqrt(x*x + y*y + z*z);
}
Vec Vec::operator=(const Vec& rhs) {
return Vec(rhs);
}
Vec Vec::operator*(const Vec& rhs) {
return Vec( x * rhs.x, y * rhs.y, z * rhs.z);
}
Vec Vec::operator*(const double rhs) {
return Vec(rhs * x, rhs * y, rhs * z);
}
Vec::Vec() :
x(std::numeric_limits<double>::signaling_NaN()),
y(std::numeric_limits<double>::signaling_NaN()),
z(std::numeric_limits<double>::signaling_NaN()) { }
Vec::Vec( double c) :
x(c), y(c), z(c) {}
Vec::Vec(const Vec & vec) :
x(vec.x), y(vec.y), z(vec.z) { }
Vec::Vec(double a, double b, double c)
: x(a), y(b), z(c) { }
You need a global operator that takes two arguments: a double and then a Vec, and it can be easily implemented by calling the operator you already have listed
inline Vec operator*(double s, const Vec& v) {
return v * s;
}
Try to create new global operator:
Vec operator*(int i, const Vec& rhs) {
return Vec(i * rhs.x, i * rhs.y, i * rhs.z);
}

Binary * Operator Not Found

I have a vector class with a properly overloaded Vect*float operator and am trying to create the global/non-member float*Vect operator as follows: (Note this is a heavily edited sample)
class Vect
{
public:
Vect::Vect(const float p_x, const float p_y, const float p_z, const float p_w);
Vect operator*(const float p_sclr) const;
private:
float x;
float y;
float z;
float w;
};
Vect::Vect(const float p_x, const float p_y, const float p_z, const float p_w) {
x = p_x;
y = p_y;
z = p_z;
w = p_w;
}
Vect Vect::operator*(const float p_sclr) const {
return Vect( (x * p_sclr), (y * p_sclr), (z * p_sclr), 1); // reset w to 1
}
//Problem Non-MemberOperator
Vect operator*(const float p_sclr, const Vect& p_vect);
Vect operator*(const float p_sclr, const Vect& p_vect) {
return p_vect * p_sclr;
}
But when I go to test the operator with the call:
Vect A(2.0f, 3.0f, 4.0f, 5.0f);
float s = 5.0f;
Vect C, D;
C = A * s; // Fine
D = s * A; // Error as below
I receive the following compile error:
error C2678: binary '*' : no operator found which takes a left-hand operand of type 'float' (or there is no acceptable conversion)
Can anyone provide insight to why this happens? The MS documentation is available at http://msdn.microsoft.com/en-us/library/ys0bw32s(v=VS.90).aspx and isn't very helpful Visual Studio 2008. This is the only compile error or warning I receive.
You still havn't posted a complete example. I can compile the following code without any problems:
class vect
{
float coeffs[4];
public:
vect()
{
for (int k=0; k<4; ++k)
coeffs[k] = 0;
}
vect(float x, float y, float z, float w)
{
coeffs[0] = x;
coeffs[1] = y;
coeffs[2] = z;
coeffs[3] = w;
}
vect operator*(float scalar) const
{
return vect(
scalar*coeffs[0],
scalar*coeffs[1],
scalar*coeffs[2],
scalar*coeffs[3] );
}
};
vect operator*(float scalar, vect const& x)
{
return x*scalar;
}
void test()
{
vect a (2,3,4,5);
float s = 5;
vect c, d;
c = a * s;
d = s * a;
}
So, the problem must lie somewhere else.
I also can compile the code without any problems (like sellibitze, who beat me to it!)
Here's the code I used:
//main.cpp
#include <iostream>
using namespace std;
class Vect
{
public:
float x,y,z,w;
Vect(const float p_x, const float p_y, const float p_z, const float p_w) {
x = p_x;
y = p_y;
z = p_z;
w = p_w;
}
Vect()
{
x=y=z=w=0;
}
Vect operator*(const float p_sclr) const {
return Vect( (x * p_sclr), (y * p_sclr), (z * p_sclr), 1); // reset w to 1
}
};
Vect operator*(const float p_sclr, const Vect& p_vect) {
return p_vect * p_sclr;
}
int main()
{
Vect A(2.0f, 3.0f, 4.0f, 5.0f);
float s = 5.0f;
Vect C, D;
C = A * s; // Fine
D = s * A; // Error as below
cout << D.x << endl;
return 0;
}
Edit: Like sellibitze suggests, the problem may lie elsewhere. Is the error you're listing the ONLY error your compiler is giving you? Also, what version of Visual Studio are you running?
Looks like 2 beat me to it, but it worked for me too - built and ran fine (VS2010, Win32 console project):
class Vect
{
public:
float x,y,z,w;
Vect::Vect(){}
Vect::Vect(const float p_x, const float p_y, const float p_z, const float p_w)
{
x = p_x;
y = p_y;
z = p_z;
w = p_w;
}
Vect Vect::operator*(const float p_sclr) const
{
return Vect( (x * p_sclr), (y * p_sclr), (z * p_sclr), 1); // reset w to 1
}
};
Vect operator*(const float p_sclr, const Vect& p_vect) { return p_vect * p_sclr;}
int _tmain(int argc, _TCHAR* argv[])
{
Vect a (2,3,4,5);
float s = 5;
Vect c, d;
c = a * s;
d = s * a;
}
The final solution was to go with a friend function because the variables were in p_vect were private:
//class definition
friend Vect operator*(const float scale, const Vect& p_vect);
//function
Vect operator*(const float p_sclr, const Vect& p_vect) {
return Vect( (p_vect.x * p_sclr), (p_vect.y * p_sclr), (p_vect.z * p_sclr), 1.0f);
}