I am not very familiar with templates in C++ so I am struggling to solve the following problem.
I have the classes Vector2D and Vector3D but I want them to inherit from a class Vector. To be able to define common functions in Vector I am using CRTP (Curiously Recurring Template Pattern).
This is a shortend version of my Vector class:
#pragma once
#include "../stdafx.h"
template <class VectorImpl>
class Vector {
public:
VectorImpl& operator=(const VectorImpl& other);
virtual const float operator*(const VectorImpl& other) const = 0;
friend const VectorImpl operator*(const float& scalar, const VectorImpl& other);
virtual VectorImpl& operator*=(const float& scalar) = 0;
float abs() const;
virtual std::string toString() const = 0;
virtual ~Vector() = 0 {};
protected:
virtual void copyFrom(const VectorImpl& other) = 0;
};
-----------------------------------------------------------------------------------------
#include "Vector.h"
#include "Vector2D.h" // edit
#include "Vector3D.h" // edit
template <class VectorImpl>
VectorImpl& Vector<VectorImpl>::operator=(const VectorImpl& other) {
this->copyFrom(other);
// edit
// return *this;
return static_cast<VectorImpl&>(*this);
}
template <class VectorImpl>
const VectorImpl operator*(const float& scalar, const VectorImpl& other) {
VectorImpl result = other;
result *= scalar;
return result;
}
template <class VectorImpl>
float Vector<VectorImpl>::abs() const {
const VectorImpl thisImpl = static_cast<const VectorImpl&>(*this); // edit
return std::sqrt(thisImpl * thisImpl);
}
// edit
template class Vector<Vector2D>;
template class Vector<Vector3D>;
And this is a shortend version of my Vector2D class:
#pragma once
#include "../stdafx.h"
#include "Vector.h"
class Vector2D :
public Vector<Vector2D> {
public:
Vector2D();
Vector2D(const Vector2D& other);
Vector2D(const float& xPos, const float& yPos);
const float operator*(const Vector2D& other) const;
Vector2D& operator*=(const float& scalar);
std::string toString() const;
~Vector2D();
protected:
void copyFrom(const Vector2D& other);
private:
float xPos;
float yPos;
};
-----------------------------------------------------------------------------------------
#include "Vector2D.h"
Vector2D::Vector2D() :
xPos(0.0f),
yPos(0.0f) {
}
Vector2D::Vector2D(const Vector2D& other) {
this->copyFrom(other);
}
void Vector2D::copyFrom(const Vector2D& other) {
if (this != &other) {
this->xPos = other.getXPos();
this->yPos = other.getYPos();
}
}
Vector2D::Vector2D(const float& xPos, const float& yPos) {
this->xPos = xPos;
this->yPos = yPos;
}
const float Vector2D::operator*(const Vector2D& other) const {
return this->xPos * other.getXPos() + this->yPos * other.getYPos();
}
Vector2D& Vector2D::operator*=(const float& scalar) {
this->xPos *= scalar;
this->yPos *= scalar;
return *this;
}
std::string Vector2D::toString() const {
std::string ret = std::to_string(this->xPos);
ret += " ";
ret += std::to_string(this->yPos);
return ret;
}
Vector2D::~Vector2D() {
// intentionally left blank
}
The problem is, for every call of a method from Vector2D (Vector3D respectively) that is implemented in Vector I get an LNK2019 error (unresolved external symbol 'symbol' referenced in function 'function').
I am quite sure that I am doing somethin wrong with my template implementation but I can't figure out what it is. I am researching for hours now.
I appreciate any help, so thanks in advance.
EDIT:
I added the necessary instantiations of my template classes but now I get casting errors. Adding
VectorImpl result = static_cast<const VectorImpl>(*this);
or
VectorImpl result = static_cast<VectorImpl>(*this);
doesn't change the problem. What I am I still missing here?
EDIT 2:
Okay of course it hast to be static_cast<const VectorImpl&>(*this).
I also added these casts but now I get that damn linking error again. This time only the functions friend operator* and abs can't be linked. I don't see much difference to the other functions. So why are they problematic?
Related
How do i fix this?
I'm getting error: 'this' argument has type const but function is not marked const c++ overload operator
template <class T>
class Rational {
private:
T n = 0;
T d = 1;
public:
Rational() = default;
T numerator() {
return n;
}
T denominator() {
return d;
}
};
template <class T>
inline bool const operator ==(const Rational <T> & lhs, const Rational <T>& rhs) {
return lhs.numerator() * rhs.denominator() == lhs.denominator() * rhs.numerator();
}
My guess is that numerator() and denominator() member functions are not const member functions. Make them const. After that, the above function should work.
BTW, there is no need for the return type to be bool const. Keep it simple and change it to bool.
If numerator() and denominator() are to be used to directly assign to Rationals internal member variables as well as being used in const contexts, you need two sets of overloads. One mutable and one const:
// mutable interface
T& Rational::numerator();
T& Rational::denominator();
// const interface if T may only be a fundamental integral type
T Rational::numerator() const;
T Rational::denominator() const;
// const interface if sizeof(T) may be > sizeof(T*)
T const& Rational::numerator() const;
T const& Rational::denominator() const;
Note, only one of the const interfaces may be used so you need to select one of them.
Here's an example of how it can be done:
#include <iostream>
#include <type_traits>
template<typename T>
class Rational {
public:
// pass by value for fundamental types, by const& for other types
using by_value_or_by_const_ref =
std::conditional_t<std::is_fundamental_v<T>, T, T const&>;
Rational(by_value_or_by_const_ref n, by_value_or_by_const_ref d) :
m_numerator(n), m_denominator(d) {}
// mutable interface
T& numerator() { return m_numerator; }
T& denominator() { return m_denominator; }
// const interface
by_value_or_by_const_ref numerator() const { return m_numerator; }
by_value_or_by_const_ref denominator() const { return m_denominator; }
private:
T m_numerator;
T m_denominator;
};
template<class T>
inline bool operator==(const Rational<T>& lhs, const Rational<T>& rhs) {
// using const interface
return lhs.numerator() * rhs.denominator() ==
lhs.denominator() * rhs.numerator();
}
int main() {
Rational<int> a(10, 20);
Rational<int> b(10, 10);
// using mutable interface
a.denominator() /= 4;
b.numerator() *= 2;
std::cout << std::boolalpha << (a == b) << "\n";
}
I am trying to call the assignment operator from the base class (shape) in the derived class (point). I get an unresolved external linker error and I don't understand why. I put "virtual" in front of the base assignment operator and placed the base assignment operator inside of my derived class at the end. Where did I go wrong?
#ifndef SHAPE_H
#define SHAPE_H
#include <iostream>
using namespace std;
namespace Joe
{
namespace CAD
{
class Shape
{
private:
int m_id;
public:
Shape(); //default constructor
~Shape(); //destructor
Shape(const Shape& s); //copy constructor
virtual Shape& operator = (const Shape& source); //assignment operator
string ToString() const; //returns id as a string
friend ostream& operator << (ostream& os, const Shape& sh); //global function that can access private members
int ID() const;
};
inline int Shape::ID() const //retrieve ID of shape
{
return m_id;
}
}
}
#endif
#ifndef POINT_H
#define POINT_H
#include <iostream>
#include "shape.h"
namespace Joe
{
namespace CAD
{
class Point: public Shape
{
private:
double m_x;
double m_y;
public:
Point(); //default constructor
~Point(); //destructor
Point(const Point& pt); //copy constructor
Point(double newX, double newY) //constructor accepting x and y coordinates
{
m_x = newX;
m_y = newY;
std::cout << "Point(" << m_x <<","<< m_y <<")" << std::endl;
}
Point(double val); //constructor accepting one double
void X(double newXval) {m_x = newXval;} //default inline setter
void Y(double newYval) {m_y = newYval;} //default inline setter
double X() const; //getter pre-inline
double Y() const; //getter pre-inline
std::string ToString() const; //returns a string description
//distance functions
double Distance() const; //calculate the distance to the origin (0,0)
double Distance(const Point& p) const; //calculate the distance between two points
//operator overloading
Point operator - () const; //negate the 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); //assignment operator
Point& operator *= (double factor); //scale the coordinates and assign
friend std::ostream& operator << (std::ostream& os, const Point& p); //send to ostream (friend)
Shape& operator = (const Shape& source); // call assignment operator of base class
};
inline double Point::X() const //normal inline getter
{
return m_x;
}
inline double Point::Y() const //normal inline getter
{
return m_y;
}
}
}
#endif
Shape& Shape::operator = (const Shape& source) //assignment operator
{
if (this == &source) //avoid self-assignment
return *this;
cout << "shape assignment" << endl;
m_id = source.m_id;
return *this;
}
Point& Point::operator = (const Point& source) //assign
{
if (this == &source) //avoid self-assignment
return *this;
m_x = source.m_x;
m_y = source.m_y;
return *this;
}
Your problem is that when you call operator = and pass it a Shape, you are calling to Point::operator=(const Shape&), which you do not define, you only define Shape::operator=(const Shape&) and Point::operator=(const Point&). You need to add Point::operator=(const Shape&), for example like this:
Shape& Point::operator = (const Shape& shape) //assign
{
const Point& source = static_cast<Point&>(shape); // or use dynamic_cast here, if you want to be safe
if (this == &source) //avoid self-assignment
return *this;
m_x = source.m_x;
m_y = source.m_y;
return *this;
}
Your problem might be that you define the class in a namespace, but you define the operators outside that namespace without specifying it. Because of this, the compiler can't connect the definition to the declaration.
Ishamael pointed out that you don't specify what happens when a non-Point Shape is assigned to a Point. This is necessary for a virtual assignment operator; see his answer. But this virtual assignment operator could end up doing a lot of unexpected things, like cutting off parts of objects if the wrong types are assigned to each other.
You don't need the virtualness to ensure that the Shape operator also gets called when Point is assigned. Just call the Shape operator inside the Point operator. Making the operator virtual would actually have the opposite effect; the Point operator would override the Shape operator even if the instance you're calling it with is referred to as a Shape.
Point& Point::operator = (const Point& source) //assign
{
if (this == &source) //avoid self-assignment
return *this;
Shape::operator=(source); // also call the base class operator
m_x = source.m_x;
m_y = source.m_y;
return *this;
}
I am using Xcode and I have provided two headers below: Spheres.h and Vector3.h which both are suppose to be templates. Vector3.h compiles without any errors.
Spheres.h do not compile and returns this warning: "Expected ')'" and points to:
Sphere(const Vector3<T>& c,const float r);
^
This error occurs at any place inside Sphere.h where I have a Vector<T>. If I remove <T> the code can compile, I do not understand. Why? I want to be able to initialise Vector3<T> with same template<typename T> as Sphere<T>.
Please help!
Sphere.h
#ifndef SPHERE
#define SPHERE
#include "Vector3.h"
template <typename T>
class Sphere
{
public:
// Constructors
// Default
Sphere();
// Copy
Sphere(const Sphere<T>& sphere);
Sphere(const Vector3<T>& c, const float r);
// Destructor
~Sphere();
// Get properties
const Vector3<T>& GetCenter() const;
const float& GetRadius() const;
// Set Properties
void SetCenter(const Vector3<T>& vector);
void SetRadius(const float& r);
// Methods
// Calculate sphere area: A = 4 * PI * r^2
const float GetArea() const;
// Calculate sphere volume: V = (4 * PI * r^3) / 3
const float GetVolume() const;
// Return if given point of vector3 is within sphere
const bool PointIntersect(const Vector3<T>& point) const;
bool Overlap(const Sphere<T>& sphere);
// Tries to load data from a string
bool Load(std::string string) const;
// Operators
// Assignment operator
Sphere<T>& operator=(const Sphere<T>& sphere);
// Less than operator <
bool operator<(const Sphere<T>& s) const;
// Greater than operator >
bool operator>(const Sphere<T>& s) const;
// Less or equal operator <=
bool operator<=(const Sphere<T>& s) const;
// Greater or equal operator >=
bool operator>=(const Sphere<T>& s) const;
// Equal operator ==
bool operator ==(const Sphere<T>& s) const;
// Not equal operator !=
bool operator!=(const Sphere<T>& s) const;
// Print a sphere to console with cout
friend std::ostream& operator<<(std::ostream& out, const Sphere<T>& s);
private:
T radius;
Vector3<T> center;
};
// Implementation
// Constructor
// Default
template<typename T>
Sphere<T>::Sphere()
{
// Created empty sphere
}
// Copy
template<typename T>
Sphere<T>::Sphere(const Sphere<T>& sphere)
{
this->SetPosition(sphere.GetPosition());
this->SetRadius(sphere.GetRadius());
this->SetCenter(sphere.GetCenter());
}
template<typename T>
Sphere<T>::Sphere(const Vector3<T>& center,const float radius)
{
this->SetPosition(center);
this->radius = radius;
}
// Destructor
template<typename T>
Sphere<T>::~Sphere()
{
// Nothing to delete.
}
// Properties
// Get
template<typename T>
const Vector3<T>& Sphere<T>::GetCenter() const
{
return center;
}
template<typename T>
const float& Sphere<T>::GetRadius() const
{
return radius;
}
// Set
template<typename T>
void Sphere<T>::SetCenter(const Vector3<T>& vector)
{
this->SetPosition(vector);
}
template<typename T>
void Sphere<T>::SetRadius(const float& r)
{
radius = r;
}
// Methods
// Calculate sphere area: A = 4 * PI * r^2
template<typename T>
const float Sphere<T>::GetArea() const
{
float temp = 4 * pi * powf(this->GetRadius(), 2);
return temp;
}
// Calcutate sphere volume: V = (4 * PI * r^3) / 3
template<typename T>
const float Sphere<T>::GetVolume() const
{
float temp = (4 * pi * powf(radius, 3))/3;
return temp;
}
// Return if given point of vector3 is within sphere
template<typename T>
const bool Sphere<T>::PointIntersect(const Vector3<T>& point) const
{
if (point.GetDistance(this->GetCenter(), point) >= this->radius)
{
return true;
}
return false;
}
template<typename T>
bool Sphere<T>::Overlap(const Sphere<T>& sphere)
{
// Calculate the distance between the two spheres
float distance = Vector3::GetDistance(sphere.GetCenter(), this->GetCenter());
// Calculate the length of both radiances
float radiusSum = sphere.radius + this->radius;
// if the length of radiance is greater than the distace -> there is a overlap
if (radiusSum > distance)
return true;
return false;
}
// Tries to load data from a string
template<typename T>
bool Sphere<T>::Load(std::string string) const
{
return false;
}
// Operators
// Asignment operator
template<typename T>
Sphere& Sphere<T>::operator=(const Sphere<T>& sphere)
{
this->SetCenter(sphere.GetCenter());
this->radius = sphere.radius;
return *this;
}
// Less than operator <
template<typename T>
bool Sphere<T>::operator<(const Sphere<T>& s) const
{
float v1 = this->GetVolume();
float v2 = s.GetVolume();
if (v1 < v2)
return true;
return false;
}
// Greater than operator >
template<typename T>
bool Sphere<T>::operator>(const Sphere<T>& s) const
{
float v1 = this->GetVolume();
float v2 = s.GetVolume();
if (v1 > v2)
return true;
return false;
}
// Less or equal operator <=
template<typename T>
bool Sphere<T>::operator<=(const Sphere<T>& s) const
{
float v1 = this->GetVolume();
float v2 = s.GetVolume();
if (v1 < v2)
return true;
if (v1 == v2)
return true;
return false;
}
// Greater or equal operator >=
template<typename T>
bool Sphere<T>::operator >=(const Sphere<T>& s) const
{
float v1 = this->GetVolume();
float v2 = s.GetVolume();
if (v1 > v2)
return true;
if (v1 == v2)
return true;
return false;
}
// Equal operator ==
template<typename T>
bool Sphere<T>::operator ==(const Sphere<T>& s) const
{
float v1 = this->GetVolume();
float v2 = s.GetVolume();
if (v1 == v2)
return true;
return false;
}
// Not equal operator !=
template<typename T>
bool Sphere<T>::operator !=(const Sphere<T>& s) const
{
float v1 = this->GetVolume();
float v2 = s.GetVolume();
if (v1 != v2)
return true;
return false;
}
// Print a sphere to console with cout
template<typename T>
std::ostream& operator<<(std::ostream& out, const Sphere<T>& s)
{
std::cout << "c:(" << s.GetCenter() << ") r:" << s.GetRadius();
return out;
}
#endif
Vector3.h
#ifndef VECTOR3
#define VECTOR3
// IO standard library
#include <iostream>
template<typename Type>
class Vector3
{
public:
// Constructor
Vector3(const Type& x, const Type& y, const Type& z);
// Copy constructor
Vector3(const Vector3<Type>& v);
// Destructor
~Vector3();
// Get properties
const Type& GetX() const;
const Type& GetY() const;
const Type& GetZ() const;
// Set properties
void SetX(const Type& value);
void SetY(const Type& value);
void SetZ(const Type& value);
// Methods
// Return length of the vector3<Type>
const float GetLength() const;
// Return the distance between two vector3<type>
const float GetDistance(const Vector3<Type>& v1, const Vector3<Type>& v2) const;
// Operators
// Assignment =
Vector3<Type>& operator=(const Vector3<Type>& v);
// Addition
Vector3<Type> operator+(const Vector3<Type>& v);
// Subtraction
Vector3<Type> operator-(const Vector3<Type>& v);
// Scalar product
float operator*(const Vector3<Type>& v);
// Multiplication
Vector3<Type> operator*(const float& s);
// Friend multiplication
friend Vector3<Type> operator*(const float& s, const Vector3<Type>& v);
// Cout: printing a vector3 to console
friend std::ostream& operator<<(std::ostream& out, const Vector3<Type>& v);
private:
Type x;
Type y;
Type z;
};
// Template implementation
// Constructor
template<typename Type>
Vector3<Type>::Vector3(const Type& x, const Type& y, const Type& z)
{
this->SetX(x);
this->SetY(y);
this->SetZ(z);
}
// Copy constructor
template<typename Type>
Vector3<Type>::Vector3(const Vector3<Type>& v)
{
this->SetX(x);
this->SetY(y);
this->SetZ(z);
}
// Destructor
template<typename Type>
Vector3<Type>::~Vector3<Type>()
{
// Nothin to delete
}
// Get Properties
template<typename Type>
const Type& Vector3<Type>::GetX() const
{
return this->x;
}
template<typename Type>
const Type& Vector3<Type>::GetY() const
{
return this->y;
}
template<typename Type>
const Type& Vector3<Type>::GetZ() const
{
return this->z;
}
// Set properties
template<typename Type>
void Vector3<Type>::SetX(const Type& value)
{
this->x = value;
}
template<typename Type>
void Vector3<Type>::SetY(const Type& value)
{
this->x = value;
}
template<typename Type>
void Vector3<Type>::SetZ(const Type& value)
{
this->x = value;
}
// Methods
// Return length of the vector3<Type>
template<typename Type>
const float Vector3<Type>::GetLength() const
{
float length = 0;
length = sqrtf(powf(x,2) + powf(y,2) + powf(z,2));
return length;
}
// Return the distance between two vector3's
template<typename Type>
const float Vector3<Type>::GetDistance(const Vector3<Type>& v1, const Vector3<Type>& v2) const
{
return sqrtf(powf((v2.x - v1.x), 2) +
powf((v2.y - v1.y), 2) +
powf((v2.z - v1.z), 2) );
}
// Operators
// Assignment
template<typename Type>
Vector3<Type>& Vector3<Type>::operator=(const Vector3<Type>& v)
{
this->SetX(v.x);
this->SetY(v.y);
this->SetZ(v.z);
return *this;
}
// Addition
template<typename Type>
Vector3<Type> Vector3<Type>::operator+(const Vector3<Type>& v)
{
Type x, y, z;
x = this->x + v.x;
y = this->y + v.y;
z = this->z + v.z;
Vector3<Type> temp(x, y, z);
return temp;
}
// Subtraction
template<typename Type>
Vector3<Type> Vector3<Type>::operator-(const Vector3<Type>& v)
{
Type x,y,z;
x = this->x - v.x;
y = this->y - v.y;
z = this->z - v.z;
Vector3<Type> temp(x, y, z);
return temp;
}
// Scalar product
template<typename Type>
float Vector3<Type>::operator*(const Vector3<Type>& v)
{
float scalarP = (this->GetX() * v.x) + (this->GetY() * v.y) + (this->GetZ() * v.z);
return scalarP;
}
template<typename Type>
Vector3<Type> Vector3<Type>::operator*(const float& s)
{
Vector3 temp(this->GetX() * s, this->GetY() * s, this->GetZ() * s);
return temp;
}
template<typename Type>
Vector3<Type> operator*(const float& s, const Vector3<Type>& v)
{
Vector3<Type> temp(v.x * s, v.y * s, v.z * s);
return temp;
}
// Cout: printing a vector3 to console
template<typename Type>
std::ostream& operator<<(std::ostream& out, const Vector3<Type>& v)
{
std::cout << "x:" << v.x
<< " y:" << v.y
<< " z:" << v.z;
return out;
}
#endif
The following compiles fine on gcc. Other than fixing the obvious syntax errors, I've also modified the constructors to fully initialize the object. Other possible solutions are to give Vector3 a default constructor (such that it can have a default initial value), or make center a Vector3<T>*.
#ifndef SPHERE
#define SPHERE
#include "vector3.h"
template <typename T>
class Sphere
{
public:
// Constructors
// Default
Sphere();
// Copy
Sphere(const Sphere<T>& sphere);
Sphere(const Vector3<T>& c, const float r);
// Destructor
~Sphere();
// Get properties
const Vector3<T>& GetCenter() const;
const float& GetRadius() const;
// Set Properties
void SetCenter(const Vector3<T>& vector);
void SetRadius(const float& r);
// Methods
// Calculate sphere area: A = 4 * PI * r^2
const float GetArea() const;
// Calculate sphere volume: V = (4 * PI * r^3) / 3
const float GetVolume() const;
// Return if given point of vector3 is within sphere
const bool PointIntersect(const Vector3<T>& point) const;
bool Overlap(const Sphere<T>& sphere);
// Tries to load data from a string
bool Load(std::string string) const;
// Operators
// Assignment operator
Sphere<T>& operator=(const Sphere<T>& sphere);
// Less than operator <
bool operator<(const Sphere<T>& s) const;
// Greater than operator >
bool operator>(const Sphere<T>& s) const;
// Less or equal operator <=
bool operator<=(const Sphere<T>& s) const;
// Greater or equal operator >=
bool operator>=(const Sphere<T>& s) const;
// Equal operator ==
bool operator ==(const Sphere<T>& s) const;
// Not equal operator !=
bool operator!=(const Sphere<T>& s) const;
// Print a sphere to console with cout
friend std::ostream& operator<<(std::ostream& out, const Sphere<T>& s);
private:
T radius;
Vector3<T> center;
};
// Implementation
// Constructor
// Default
template<typename T>
Sphere<T>::Sphere()
: radius(0), center(Vector3<T>(0,0,0))
{
// Created empty sphere
}
// Copy
template<typename T>
Sphere<T>::Sphere(const Sphere<T>& sphere)
: radius(sphere.radius), center(sphere.center)
{
}
template<typename T>
Sphere<T>::Sphere(const Vector3<T>& center, const float radius)
: radius(radius), center(center)
{
}
// Destructor
template<typename T>
Sphere<T>::~Sphere()
{
// Nothing to delete.
}
// Properties
// Get
template<typename T>
const Vector3<T>& Sphere<T>::GetCenter() const
{
return center;
}
template<typename T>
const float& Sphere<T>::GetRadius() const
{
return radius;
}
// Set
template<typename T>
void Sphere<T>::SetCenter(const Vector3<T>& vector)
{
this->SetPosition(vector);
}
template<typename T>
void Sphere<T>::SetRadius(const float& r)
{
radius = r;
}
// Methods
const float pi = 3.14;
// Calculate sphere area: A = 4 * PI * r^2
template<typename T>
const float Sphere<T>::GetArea() const
{
float temp = 4 * pi * powf(this->GetRadius(), 2);
return temp;
}
// Calcutate sphere volume: V = (4 * PI * r^3) / 3
template<typename T>
const float Sphere<T>::GetVolume() const
{
float temp = (4 * pi * powf(radius, 3))/3;
return temp;
}
// Return if given point of vector3 is within sphere
template<typename T>
const bool Sphere<T>::PointIntersect(const Vector3<T>& point) const
{
if (point.GetDistance(this->GetCenter(), point) >= this->radius)
{
return true;
}
return false;
}
template<typename T>
bool Sphere<T>::Overlap(const Sphere<T>& sphere)
{
// Calculate the distance between the two spheres
float distance = Vector3<T>::GetDistance(sphere.GetCenter(), this->GetCenter());
// Calculate the length of both radiances
float radiusSum = sphere.radius + this->radius;
// if the length of radiance is greater than the distace -> there is a overlap
if (radiusSum > distance)
return true;
return false;
}
// Tries to load data from a string
template<typename T>
bool Sphere<T>::Load(std::string string) const
{
return false;
}
// Operators
// Asignment operator
template<typename T>
Sphere<T>& Sphere<T>::operator=(const Sphere<T>& sphere)
{
this->SetCenter(sphere.GetCenter());
this->radius = sphere.radius;
return *this;
}
// Less than operator <
template<typename T>
bool Sphere<T>::operator<(const Sphere<T>& s) const
{
float v1 = this->GetVolume();
float v2 = s.GetVolume();
if (v1 < v2)
return true;
return false;
}
// Greater than operator >
template<typename T>
bool Sphere<T>::operator>(const Sphere<T>& s) const
{
float v1 = this->GetVolume();
float v2 = s.GetVolume();
if (v1 > v2)
return true;
return false;
}
// Less or equal operator <=
template<typename T>
bool Sphere<T>::operator<=(const Sphere<T>& s) const
{
float v1 = this->GetVolume();
float v2 = s.GetVolume();
if (v1 < v2)
return true;
if (v1 == v2)
return true;
return false;
}
// Greater or equal operator >=
template<typename T>
bool Sphere<T>::operator >=(const Sphere<T>& s) const
{
float v1 = this->GetVolume();
float v2 = s.GetVolume();
if (v1 > v2)
return true;
if (v1 == v2)
return true;
return false;
}
// Equal operator ==
template<typename T>
bool Sphere<T>::operator ==(const Sphere<T>& s) const
{
float v1 = this->GetVolume();
float v2 = s.GetVolume();
if (v1 == v2)
return true;
return false;
}
// Not equal operator !=
template<typename T>
bool Sphere<T>::operator !=(const Sphere<T>& s) const
{
float v1 = this->GetVolume();
float v2 = s.GetVolume();
if (v1 != v2)
return true;
return false;
}
// Print a sphere to console with cout
template<typename T>
std::ostream& operator<<(std::ostream& out, const Sphere<T>& s)
{
std::cout << "c:(" << s.GetCenter() << ") r:" << s.GetRadius();
return out;
}
#endif
It is because your class Sphere requires Vector3 as template class. Like here:
~Sphere();
// Get properties
const Vector3<T>& GetCenter() const;
const float& GetRadius() const;
// Set Properties
But when you provide Sphere with Vector3<T> it will result in someting like this Vector3<T><T>
I have a class:
class Point3D : public Point{
protected:
float x;
float y;
float z;
public:
Point3D(){x=0; y=0; z=0;}
Point3D(const Point3D & point){x = point.x; y = point.y; z = point.z;}
Point3D(float _x,float _y,float _z){x = _x; y = _y; z = _z;}
inline const Point3D operator+(const Vector3D &);
const Point3D & operator+(const Point3D &point){
float xT = x + point.getX();
float yT = y + point.getY();
float zT = z + point.getZ();
return Point3D(xT, yT, zT);
}
...
When I use it that way:
Point3D point = Point3D(10,0,10);
Everything works fine.
When I write:
Point3D point = Point3D(10,0,10);
Point3D point2 = Point3D(0,0,0) + point();
Also it's ok (point2 = point). When I add something more than (0,0,0) it's also working.
But when I want just to:
Point3D point = Point3D(10,0,10);
someFunction( Point3D(0,0,0) + point ); //will get strange (x,y,z)
The function get value of some (in my opinion) random (x,y,z). Why?
What's even stranger, in that similar example everything will be working again:
Point3D point = Point3D(10,0,10);
Point3D point2 = Point3D(0,0,0) + point;
someFunction( point2 ); // will get (10,0,10)
What's the reason for that strange behaviour?
The operator+() is returning a dangling reference, the returned reference is referring to a Point3D instance that is destroyed when operator+() returns. Change to:
Point3D operator+(const Point3D &point) const {
so a copy is returned, and make it const as it has no reason to be changing anything.
The typical pattern for classes that support arithmetic operators is
class Foo
{
public:
Foo & operator+=(Foo const & rhs) { /* ... */ return *this; }
Foo & operator-=(Foo const & rhs) { /* ... */ return *this; }
Foo & operator*=(Foo const & rhs) { /* ... */ return *this; }
Foo & operator/=(Foo const & rhs) { /* ... */ return *this; }
};
Foo operator+(Foo const & lhs, Foo const & rhs) { return Foo(lhs) += rhs; }
Foo operator-(Foo const & lhs, Foo const & rhs) { return Foo(lhs) -= rhs; }
Foo operator*(Foo const & lhs, Foo const & rhs) { return Foo(lhs) *= rhs; }
Foo operator/(Foo const & lhs, Foo const & rhs) { return Foo(lhs) /= rhs; }
You are returning a reference to a local variable from operator+ which will get invalidated once the function returns, you need to return a copy of the Point3D created.
How can I modify the following code in such way I don't need to repeat f2=11;
f3=12; in the main function. The code is for overloading the most common operators.
class FLOAT{
private:
float x;
public:
FLOAT(){ x=0.0; }
void setFloat(float f) { x=f; }
float getFloat() { return x;};
FLOAT operator+(FLOAT obj) {x=x+obj.x; return *this;};
FLOAT operator-(FLOAT obj) {x=x-obj.x; return *this;};
FLOAT operator*(FLOAT obj) {x=x*obj.x; return *this;};
FLOAT operator/(FLOAT obj) {x=x/obj.x; return *this;};
FLOAT& operator=(const FLOAT& obj) {this->x=obj.x; return *this; };
FLOAT& operator=(const float& y) {this->x=y; return *this; };
};
int main() {
FLOAT f,f2,f3;
f2=11;
f3=12;
f=f3-f2;
cout<<"f3-f2 ="<<f.getFloat()<<endl;
f2=11;
f3=12;
f=f3+f2;
cout<<"f3+f2 ="<<f.getFloat()<<endl;
f2=11;
f3=12;
f=f3*f2;
cout<<"f3*f2 ="<<f.getFloat()<<endl;
f2=11;
f3=12;
f=f3/f2;
cout<<"f3/f2 ="<<f.getFloat()<<endl;
system("pause"); // to pause console screen
return 0;
}
#Oli's answer pretty much says you what minimal thing you need to do in order to make your code work. However, I see (and I know even #Oli sees) that your implementation of the class has many flaws.
Since you've implemented FLOAT, I'm explaining you the implementation of Double (the implementation of FLOAT would be similar).
class Double {
double data;
public:
Double (double p=0.0) : data(p){}
double value() { return data; }
Double & operator+=(Double const & other)
{
data += other.data;
return *this;
}
Double & operator-=(Double const & other)
{
data -= other.data;
return *this;
}
//...
};
Note that you don't need to implement operator=(Double const&) and Double(Double const&). The compiler generated ones would be enough. Since the constructor takes one argument of type double, you don't need to implement operator=(double const &) also. The compiler generated copy-semantics, along with the constructor, would take care of that.
Now see this,
//implement operator+ and operator- as non-member functions
Double operator+(Double a, Double const & b)
{
a += b; //a is local copy, so we can change it
return a;
}
Double operator-(Double a, Double const & b)
{
a -= b; //a is local copy, so we can change it
return a;
}
Note that I've implemented operator+ and operator- in terms of operator+= and operator-= respectively.
Similarly, you can implement operator/= and operator*= as member functions, and then implement operator/ and operator* in terms of the them!
Your operators should create a new instance; they shouldn't be modifying themselves (in fact, they should be declared const to prevent this).
e.g.:
FLOAT operator+(FLOAT obj) const
{
FLOAT tmp;
tmp.setFloat(x + obj.x);
return tmp;
}
Note there are much more idiomatic ways of defining operator overloads (e.g. defining operator+ in terms of operator+=, and defining a constructor that takes a float). But the above should suffice.