I'm having an issue with the inheritance of my operator overloading functions in my derived class.
#pragma once
#include "Math.hpp"
using namespace Math;
class Euler
{
public:
float x, y, z;
Euler();
Euler(const float &, const float &, const float &);
float &operator[](const char &) const;
Euler &operator=(const Euler &);
Euler &operator+=(const Euler &);
Euler &operator-=(const Euler &);
Euler &operator*=(const float &);
Euler &operator/=(const float &);
Euler operator+(const Euler &) const;
Euler operator-(const Euler &) const;
Euler operator*(const float &) const;
Euler operator/(const float &) const;
bool operator==(const Euler &) const;
bool operator!=(const Euler &) const;
bool IsValid() const;
void Clear();
};
inline Euler::Euler()
{
x = y = z = 0.f;
}
inline Euler::Euler(const float &_x, const float &_y, const float &_z)
{
x = _x;
y = _y;
z = _z;
}
inline float &Euler::operator[](const char &c) const
{
return ((float *)this)[c];
}
inline Euler &Euler::operator=(const Euler &e)
{
x = e.x;
y = e.y;
z = e.z;
return *this;
}
inline Euler &Euler::operator+=(const Euler &e)
{
x += e.x;
y += e.y;
z += e.z;
return *this;
}
inline Euler &Euler::operator-=(const Euler &e)
{
x -= e.x;
y -= e.y;
z -= e.z;
return *this;
}
inline Euler &Euler::operator*=(const float &e)
{
x *= e;
y *= e;
z *= e;
return *this;
}
inline Euler &Euler::operator/=(const float &e)
{
x /= e + M_FLT_EPSILON;
y /= e + M_FLT_EPSILON;
z /= e + M_FLT_EPSILON;
return *this;
}
inline Euler Euler::operator+(const Euler &e) const
{
return Euler(x + e.x, y + e.y, z + e.z);
}
inline Euler Euler::operator-(const Euler &e) const
{
return Euler(x - e.x, y - e.y, z - e.z);
}
inline Euler Euler::operator*(const float &f) const
{
return Euler(x * f, y * f, z * f);
}
inline Euler Euler::operator/(const float &f) const
{
return Euler(x / (f + M_FLT_EPSILON), y / (f + M_FLT_EPSILON), z / (f + M_FLT_EPSILON));
}
inline bool Euler::operator==(const Euler &e) const
{
return e.x == x && e.y == y && e.z == z;
}
inline bool Euler::operator!=(const Euler &e) const
{
return e.x != x || e.y != y || e.z != z;
}
inline bool Euler::IsValid() const
{
using namespace std;
return isfinite(x) && isfinite(y) && isfinite(z);
}
inline void Euler::Clear()
{
x = y = z = 0.f;
}
class Vector : public Euler
{
public:
using Euler::Euler;
void Rotate(const Angle &);
void Rotate2D(const float &);
float Length() const;
float LengthSqr() const;
float Length2D() const;
float Length2DSqr() const;
float DistTo(const Vector &) const;
float DistToSqr(const Vector &) const;
};
inline float Vector::Length() const
{
return Sqrt((x * x) + (y * y) + (z * z));
}
inline float Vector::LengthSqr() const
{
return (x * x) + (y * y) + (z * z);
}
inline float Vector::Length2D() const
{
return Sqrt((x * x) + (y * y));
}
inline float Vector::Length2DSqr() const
{
return (x * x) + (y * y);
}
inline float Vector::DistTo(const Vector &v) const
{
return (*this - v).Length();
}
inline float Vector::DistToSqr(const Vector &v) const
{
return (*this - v).LengthSqr();
}
The code shown below contains an error in the distto and DistToSqr function wherein it calculates (*this - v) as the superclass Euler and therefore cannot find the length function.
I was wondering why this would be as this code compiles on my laptop and not my desktop.
I'd be grateful if anyone could show me why this code doesn't work and what is the best course in fixing it.
It seems like doing this is a plausible way to fix it.
inline float Vector::DistTo(const Vector &v) const
{
Vector tmp = (*this - v);
return tmp.Length();
}
Still wondering if this is the best option to fix it though.
I'm going to assume that it is likely that Euler is always used as a base type of a more specific type? If so, you can might be able to solve this using the CRTP pattern. Here is a subset of your code in this style:
#include <cmath>
template <typename Derived>
class Euler
{
public:
float x, y, z;
Euler();
Euler(const float &, const float &, const float &);
template <typename T>
Derived & operator-=(Euler<T> const &);
template <typename T>
Derived operator-(Euler<T> const &) const;
private:
Derived & derived() const {
return static_cast<Derived &>(*this);
}
Derived const & derived() {
return static_cast<Derived const &>(*this);
}
};
template <typename Derived>
Euler<Derived>::Euler() : x(0), y(0), z(0)
{}
template <typename Derived>
Euler<Derived>::Euler(const float &_x, const float &_y, const float &_z)
: x(_x), y(_y), z(_z)
{}
template <typename Derived>
template <typename T>
Derived & Euler<Derived>::operator-=(Euler<T> const & e)
{
x -= e.x;
y -= e.y;
z -= e.z;
return derived();
}
template <typename Derived>
template <typename T>
Derived Euler<Derived>::operator-(Euler<T> const & e) const
{
return Derived(x - e.x, y - e.y, z - e.z);
}
class Vector : public Euler<Vector>
{
public:
using Euler<Vector>::Euler;
float Length() const;
float DistTo(const Vector &) const;
};
inline float Vector::Length() const
{
return std::sqrt(x * x + y * y + z * z);
}
inline float Vector::DistTo(const Vector & v) const
{
return (*this - v).Length();
}
Related
I am experimenting with lambda functions and managed to recreate a "get" functionality in C++. I can get the return value of a function without using parentheses. This is an example class, where I implement this:
using namespace std;
struct Vector2 {
float x;
float y;
float length = [&]()-> float {return sqrt(x * x + y * y); }();
float angle = [&]()-> float {return atan2(y, x); }();
Vector2() : x(0), y(0) {}
Vector2(float a, float b) : x(a), y(b) {}
~Vector2() {}
Vector2(Vector2& other) : x(other.x), y(other.y) {}
Vector2(Vector2&& other) = delete;
void operator =(Vector2&& other) noexcept{
x = other.x;
y = other.y;
}
};
int main()
{
Vector2 vec = Vector2(10, 17);
printf("%f\n%f\n%f\n%f\n", vec.x, vec.y, vec.length, vec.angle);
}
However, I am currently trying to also recreate the "set" functionality that C# has. But I'm failing. I tried to add this:
void angle = [&](float a)->void {
float l = length;
x = cos(a) * l;
y = sin(a) * l;
};
But am getting "Incomplete type is not allowed" error. I'm not sure if that's how it should look, even if I wasn't getting the error. Is it even possible to recreate the "set" functionality C# has in C++?
I know that I can just use a method SetAngle(float a){...}, but that's not really the point.
TL;DR: Don't
What you have isn't a getter, it's just a normal data member that's calculated once when the object is initialized.
In general, C++ doesn't support C#-style properties. The usual C++-style solution is to just use a pair of member functions (and maybe a data member, if you need to save the value separately), i.e.
struct Vector2 {
// ...
float length() const { return sqrt(x * x + y * y); }
void length(float l) {
float angle = angle();
float new_x = l * cos(angle);
float new_y = l * sin(angle);
x = new_x;
y = new_y;
}
// ...
};
You can get something close to a C#-style property, but you'll always run into edge-cases where they don't work perfectly. For example, here's something that will work in many cases:
template <typename T>
class Property
{
private:
std::function<T()> getter_;
std::function<void(const T&)> setter_;
public:
Property(std::function<T()> getter, std::function<void(const T&)> setter)
: getter_{getter},
setter_{setter}
{}
operator T()
{
return getter_();
}
const T& operator=(const T& val)
{
setter_(val);
return val;
}
};
struct Vector2
{
float x;
float y;
Property<float> length{
[this]() { return sqrt(x * x + y * y); },
[this](float l) {
float new_x = l * cos(angle);
float new_y = l * sin(angle);
x = new_x;
y = new_y;
}
}
Property<float> angle{
[this]() { return atan2(y, x); },
[this](float a) {
float l = length;
x = cos(a) * l;
y = sin(a) * l;
}
}
// ...
};
int main() {
Vector2 v;
v.x = 1;
v.y = 1;
v.angle = std::numbers::pi / 2;
std::cout << "(" << v.x << ", " << v.y << ")\n";
}
But this still falls apart in the edge cases, especially when you mix it with templates and/or auto type-deduction. For instance:
Vector2 v;
v.x = 1;
v.y = 1;
auto old_angle = v.angle;
v.angle = std::numbers::pi / 2;
// oops, this prints pi/2, not pi/4 like you probably expected
// because old_angle isn't a float, it's a Property<float> that
// references v
std::cout << old_angle << '\n';
Note also that there's a bug here. Consider this:
int main() {
Vector2 v1;
v1.x = 1;
v1.y = 1;
Vector2 v2 = v1;
v2.angle = std::numbers::pi / 2;
// Oops, assigning to v2.angle modified v1
std::cout << "(" << v1.x << ", " << v1.y << ")\n";
}
You could work around these issues by making Property non-copyable, but then you force any class that uses it to implement a custom copy-constructor. Also, while that would make the auto case "safe", it does so by turning it into a compile error. Still not ideal.
I agree with Miles. This is not the greatest idea, because it's unnatural for C++ developers, and you should write code that is first and foremost easy to read.
However, as an engineering challenge, here's a possible implementation:
#include <math.h>
#include <iostream>
template <typename T>
class Member
{
public:
operator T() const { return _value; }
void operator =(const T& value) const { _value = value; } void operator =(T&& value) { _value = std::move(value); }
private:
T _value;
};
class Angle
{
public:
Angle(const Member<float>& x, const Member<float>& y) :
_x(x), _y(y) {}
operator float() const { return atan2(_y, _x); }
private:
const Member<float>& _x, _y;
};
class Obj
{
public:
Member<float> x, y;
Angle angle;
Obj() : angle(this->x, this->y) {}
};
int main()
{
Obj o;
o.x = 3;
o.y = 5;
std::cout << o.x << ", " << o.y << " -> " << o.angle << std::endl;
}
While other solutions also seem to be possible, this one seems to be the most elegant :P
using namespace std;
struct Vector2 {
float x;
float y;
float init_length = [&]()-> float {return sqrt(x * x + y * y); }();
float init_angle = [&]()-> float {return atan2(y, x); }();
__declspec(property(get = GetAngle, put = SetAngle)) float angle;
__declspec(property(get = GetLength, put = SetLength)) float length;
Vector2() : x(0), y(0) {}
Vector2(float a, float b) : x(a), y(b) {}
~Vector2() {}
Vector2(Vector2& other) : x(other.x), y(other.y) {}
Vector2(Vector2&& other) = delete;
void operator =(Vector2&& other) = delete;
void Display() {
printf("%f\n%f\n%f\n%f\n\n", x, y, length, angle);
}
float GetLength() {
return sqrt(x * x + y * y);
}
float GetAngle() {
return atan2(y, x);
}
void SetLength(float l) {
float a = GetAngle();
x = cos(a) * l;
y = sin(a) * l;
}
void SetAngle(float a) {
float l = GetLength();
x = cos(a) * l;
y = sin(a) * l;
}
};
int main()
{
Vector2 vec = Vector2(10, 17);
vec.Display();
vec.length = 5;
vec.Display();
}
So i'm very new to c++ and i'm trying to test out the simple features it has. I currently have a problem that there is a 'class' type redefinition and I can't figure out why. I have used #pregama once in the header file, but still. I have even tried #ifndef and #define, but they did not work either. I'm using Visual studio 2019 community if that has anything to do with this.
Main.cpp
#include <iostream>
#include "Vectors.h"
using namespace std;
int main() {
double distance = Vector2::Zero().Distance(Vector2(1, 1));
cout << distance;
return 0;
}
Vector2.cpp
#include "Vectors.h"
#include <cmath>
class Vector2 {
public:
double x;
double y;
Vector2(double x, double y) {
this->x = x;
this->y = y;
}
static Vector2 Zero() {
return Vector2(0, 0);
}
static Vector2 One() {
return Vector2(1, 1);
}
double Distance(Vector2 other) {
Vector2 relPos = this->operator-(other);
relPos.x = abs(relPos.x);
relPos.y = abs(relPos.y);
return sqrt(pow(relPos.x, 2) + pow(relPos.y, 2));
}
Vector2 operator + (Vector2 vec) {
return Vector2(x + vec.x, y + vec.y);
}
Vector2 operator - (Vector2 vec) {
return Vector2(x - vec.x, y - vec.y);
}
Vector2 operator * (Vector2 vec) {
return Vector2(x * vec.x, y * vec.y);
}
Vector2 operator / (Vector2 vec) {
return Vector2(x / vec.x, y / vec.y);
}
};
Vectors.h
#pragma once
class Vector2 {
public:
Vector2(double x, double y);
static Vector2 Zero();
static Vector2 One();
double Distance(Vector2 other);
Vector2 operator + (Vector2 vec);
Vector2 operator - (Vector2 vec);
Vector2 operator * (Vector2 vec);
Vector2 operator / (Vector2 vec);
};
You're defining the class once in the header and once in the C++ file. You don't want to do class Vector2 { in the C++ file. Your functions should look like this
Vector2 Vector2::operator+(Vector2 vec) {
return Vector2(x + vec.x, y + vec.y);
}
And should be defined at top-level scope in the C++ file.
First of all, I agree with Silvio Mayolo, You're defining the class once in the header and once in the C++ file. You don't use the keyword class in your cpp file.
And then you need to distinguish between class Vector2 and Vector2(double x, double y); As far as I'm concerned you should try to use Vector2::.
Here is my code:
Vectors.h:
#pragma once
class Vector2 {
public:
double x;
double y;
Vector2(double x, double y);
static Vector2 Zero();
static Vector2 One();
double Distance(Vector2 other);
Vector2 operator + (Vector2 vec);
Vector2 operator - (Vector2 vec);
Vector2 operator * (Vector2 vec);
Vector2 operator / (Vector2 vec);
};
Vector2.cpp:
#include "Vectors.h"
#include <cmath>
double x;
double y;
Vector2::Vector2(double x, double y)
{
this->x = x;
this->y = y;
}
Vector2 Vector2::Zero() {
return Vector2(0, 0);
}
Vector2 Vector2::One() {
return Vector2(1, 1);
}
double Vector2::Distance(Vector2 other) {
Vector2 relPos = this->operator-(other);
relPos.x = abs(relPos.x);
relPos.y = abs(relPos.y);
return sqrt(pow(relPos.x, 2) + pow(relPos.y, 2));
}
Vector2 Vector2::operator + (Vector2 vec) {
return Vector2(x + vec.x, y + vec.y);
}
Vector2 Vector2::operator - (Vector2 vec) {
return Vector2(x - vec.x, y - vec.y);
}
Vector2 Vector2::operator * (Vector2 vec) {
return Vector2(x * vec.x, y * vec.y);
}
Vector2 Vector2::operator / (Vector2 vec) {
return Vector2(x / vec.x, y / vec.y);
}
Main.cpp:
#include <iostream>
#include "Vectors.h"
using namespace std;
int main() {
double distance = Vector2::Zero().Distance(Vector2(1, 1));
cout << distance;
return 0;
}
So I'm following along with this book called SDL Game Development by Shaun Mitchell. I've ran into a few hiccups with code from the book but have so far been able to figure it out and correct on my own but this one has got me in a bind.
The program compiles fine but crashes with a seg fault.
This is the Vector2D class that the book has me write:
#ifndef __Vector2D__
#define __Vector2D__
#include <math.h>
class Vector2D
{
public:
Vector2D(float x, float y) : m_x(x), m_y(y) {}
float getX() { return m_x; }
float getY() { return m_y; }
void setX(float x) { m_x = x; }
void setY(float y) { m_y = y; }
float length() { return sqrt(m_x * m_x + m_y * m_y); }
Vector2D operator+(const Vector2D& v2) const
{
return Vector2D(m_x + v2.m_x, m_y + v2.m_y);
}
friend Vector2D& operator+=(Vector2D& v1, const Vector2D& v2)
{
v1.m_x += v2.m_x;
v1.m_y += v2.m_y;
return v1;
}
Vector2D operator*(float scalar)
{
return Vector2D(m_x * scalar, m_y * scalar);
}
Vector2D& operator*=(float scalar)
{
m_x *= scalar;
m_y *= scalar;
return *this;
}
Vector2D operator-(const Vector2D& v2) const
{
return Vector2D(m_x - v2.m_x, m_y - v2.m_y);
}
friend Vector2D& operator-=(Vector2D& v1, const Vector2D& v2)
{
v1.m_x -= v2.m_x;
v1.m_y -= v2.m_y;
return v1;
}
Vector2D operator/(float scalar)
{
return Vector2D(m_x / scalar, m_y / scalar);
}
Vector2D& operator/=(float scalar)
{
m_x /= scalar;
m_y /= scalar;
return *this;
}
void normalize()
{
float l = length();
if (l > 0)
{
(*this) *= 1 / 1;
}
}
private:
float m_x;
float m_y;
};
#endif // __Vector2D__
This is a Player class' input handling event where the program begins to crash:
void Player::handleInput()
{
Vector2D* vec = TheInputHandler::Instance()->getMousePosition();
m_velocity = (*vec - m_position) / 100;
}
It crashes at m_velocity = (*vec - m_position) / 100; which of course traces back to my Vector2D class' operator-. m_velocity and m_position are both Vector2Ds. Replacing the - with + produces the same crash.
Any help with what may be wrong would be super appreciated.
Vector2D* vec = TheInputHandler::Instance()->getMousePosition();
You made it a pointer, but never allocated memory for it. (unless that's what that function does..?)
There is no need to make this a pointer if you're not going to pass it anywhere.
So, basically I created a Float class to track down the range of floating point values used in the program. I just replace float in my program with Float. However, the output of my program changes when I use this class, but I can't figure out where is the problem.
#define real float
class Float
{
private:
real data;
static real minVal;
static real maxVal;
static void updateMinMax( real x )
{
if ( x < minVal )
minVal = x;
if ( x > maxVal )
maxVal = x;
}
public:
static real getMin()
{
return minVal;
}
static real getMax()
{
return maxVal;
}
Float()
{
data = 0;
}
Float(real x)
{
data = x;
updateMinMax(data);
}
void setFloat( real x )
{
data = x;
updateMinMax(data);
}
void setMaxOf( real x, real y )
{
data = (x > y)? x : y;
updateMinMax(data);
}
void setInt( int x )
{
data = x;
updateMinMax(data);
}
real getFloat() const
{
return data;
}
operator int() const { return (int)data; }
void operator=(Float x)
{
data = x.data;
updateMinMax( data );
}
Float operator+(const Float& x) const
{
updateMinMax( data + x.data );
return Float(data + x.data);
}
void operator+=(Float x)
{
data += x.data;
updateMinMax( data );
}
Float operator-(const Float& x) const
{
updateMinMax( data - x.data );
return Float(data - x.data);
}
Float operator-() const
{
updateMinMax( -data );
return Float(-data);
}
void operator-=(Float x)
{
data -= x.data;
updateMinMax( data );
}
Float operator*(const Float& x) const
{
updateMinMax( data * x.data );
return Float(data * x.data);
}
void operator*=(Float x)
{
data *= x.data;
updateMinMax( data );
}
Float operator/(const Float& x) const
{
updateMinMax( data / x.data );
return Float(data / x.data);
}
void operator/=(Float x)
{
data /= x.data;
updateMinMax( data );
}
bool operator<(const Float& x) const
{
return data < x.data;
}
bool operator<=(const Float& x) const
{
return data <= x.data;
}
bool operator>(const Float& x) const
{
return data > x.data;
}
bool operator>=(const Float& x) const
{
return data >= x.data;
}
bool operator==(const Float& x) const
{
return data == x.data;
}
friend ostream& operator<<(ostream& o, Float& x)
{
o << x.data;
return o;
}
friend istream& operator>>(istream& i, Float& x)
{
i >> x.data;
return i;
}
};
The following test program demonstrates at least one difference between using a float and your Float class:
void test(float x)
{
cout<<"Called with float argument"<<endl;
}
void test(int x)
{
cout<<"Called with int argument"<<endl;
}
int main() {
Float arg1;
float arg2;
test(arg1);
test(arg2);
return 0;
}
Output:
Called with int argument
Called with float argument
I am using a class to represent a rotation angle...
class RotationAngle
{
protected:
float cosval;
float sinval;
__forceinline RotationAngle(float c, float s) { cosval = c; sinval = s; }
public:
__forceinline RotationAngle(float radians) { Set(radians); }
__forceinline RotationAngle(const RotationAngle& r) { Set(r); }
__forceinline void Set(float radians) { cosval = cos(radians); sinval = sin(radians); }
__forceinline void Set(const RotationAngle& r) { cosval = r.cosval; sinval = r.sinval; }
__forceinline float Cos() const { return cosval; }
__forceinline float Sin() const { return sinval; }
__forceinline RotationAngle& operator = (float radians) { Set(radians); return *this; }
__forceinline int operator == (const RotationAngle& r) const { return (r.cosval == cosval) && (r.sinval == sinval); }
__forceinline int operator != (const RotationAngle& r) const { return (r.cosval != cosval) || (r.sinval != sinval); }
};
I use this so I can add an angle to a point or line using an operator, and have the sine and cosine pre-calculated. It would be redundant to recalculate the sine and cosine of the angles every time the point was rotated by the same angle.
class Point
{
public:
float x;
float y;
__forceinline void Set(float sx, float sy) { x = sx; y = sy; }
__forceinline void Rotate(const RotationAngle& a) { Set(x * a.Cos() - y * a.Sin(), x * a.Sin() + y * a.Cos()); }
__forceinline void operator += (const RotationAngle& a) { Rotate(a); }
};
I would like to include a -= operator to use the negative representation of a RotationAngle (ie counterclockwise rotation). Will simply using -cos and -sin work? I'm not sure considering the formula for adding sin/cos is not as straightforward. Is there a quick way to accomplish this?
Negating an angle will negate its sine, but leave its cosine unchanged. So it might make sense to define a unary negation:
RotationAngle operator-() const {return RotationAngle(cosval, -sinval);}
and then define -= in terms of that
void operator -= (const RotationAngle& a) { Rotate(-a); }