Unexpected output zero - c++

I'm new to C++ and currently practicing on a Singly Linked List. Somehow the output of the code below is always zero. I think the problem is the nextPoint Method but however I try to change the reference/dereference, it doesn't work.
Where is the problem? Thank you in advance.
// Singly Linked List
#include <math.h>
#include <iostream>
class Point {
public:
double x, y;
Point* next;
// constructor
Point (double x, double y) {
this->x = x;
this->y = y;
this->next = NULL;
}
void nextPoint(Point nexti) {
this->next = &nexti;
}
double dist(Point &a, Point &b) {
double dx = a.x - b.x;
double dy = a.y - b.y;
return sqrt(dx*dx - dy*dy);
}
double length() {
Point *iter = this;
double len = 0.0;
while (iter->next != NULL) {
len += dist(*iter, *iter->next);
iter = iter->next;
}
return len;
}
};
int main() {
Point p1(1,1);
Point p2(2,2);
Point p3(5,5);
p1.nextPoint(p2);
p2.nextPoint(p3);
std::cout << p1.length() << std::endl;
return 1;
}

Please turn on more compiler warnings and you'll probably get a warning that in nextPoint you are storing the address of a temporary variable (nexti) permanently (in this->next).
You must either pass the address of or a reference to the point to add.
void nextPoint(Point *nexti) {
this->next = nexti;
}
p1.nextPoint(&p2);
p2.nextPoint(&p3);
or
void nextPoint(Point &nexti) {
this->next = &nexti;
}
p1.nextPoint(p2);
p2.nextPoint(p3);
Side note: please replace NULL with nullptr.

There are two problems with your code:
nextPoint takes its parameter by value, which means you're storing the address of that by-value parameter which becomes invalid as soon as the execution of nextPoint ends. Change it to accept Point &nexti.
Your distance computation function is wrong. You should be adding the squares, not subtracting them: return sqrt(dx*dx + dy*dy);
Unrelated to your question, but there are several ways in which you could improve your code:
Use the mem-initialiser list in the constructor to initialise members instead of assigning to them. This is a good habit to get into, as it will come useful once you start dealing with things where initialisation and assignment are substantially different (references, classes, ...).
Point (double x, double y) : x(x), y(y), next(nullptr)
{}
Use nullptr instead of NULL, since the latter is not type-safe.
length should be marked const, because it does not modify the object on which it's called. Note that iter has likewise been changed to const Point *:
double length() const {
const Point *iter = this;
double len = 0.0;
while (iter->next != NULL) {
len += dist(*iter, *iter->next);
iter = iter->next;
}
return len;
}
dist does not use this at all, and so it could (and should) be made a static member function. Also, it should take its parameters by const &, because it doesn't modify them:
static double dist(const Point &a, const Point &b) {
double dx = a.x - b.x;
double dy = a.y - b.y;
return sqrt(dx*dx - dy*dy);
}

Related

How do I feed a function containing a vector with different data types with these different data types?

I am still struggling to realize what I want to do.
My code shall take user-defined segments (e.g. either a line, a circle, or whatever geometric segment definition I will implement) and chain them together in a vector. However, the order of segment type ("line", "circle",...) is user-defined and may hence vary from execution to execution.
Before I go on: Each segment has different input data needed for its own creation (e.g. a line has no radius, only starting and ending point).
My preferred approach would be to
read user input and identify order of segments
create each segment
Feed these to a function (e.g. member function/method for a class implementing the contour).
This function creates the contour, e.g. by implementing a vector.
My current test code has a hard-coded segment sequence but the trick that I want to achieve is that the order (and number) of segments is not hard-coded. Unfortunately I cannot figure out how.
Here's the code:
#include <iostream>
#include <vector>
struct point
{
double x;
double y;
};
class segment
{
public:
segment()
{
P1.x = 0;
P1.y = 0;
P2.x = 0;
P2.y = 0;
};
virtual ~segment() {};
virtual double get_radius() { return 0; };
virtual double get_length() { return 0; };
virtual double get_angle() { return 0; };
int segment_id = 0;
protected:
point P1;
point P2;
};
class Line : public segment
{
public:
Line() {};
Line(const point pt1, const point pt2)
{
P1.x = pt1.x;
P1.y = pt1.y;
P2.x = pt2.x;
P2.y = pt2.y;
segment_id = 1;
};
~Line() {};
double get_length() { return calc_length(); };
double get_angle() { return calc_angle(); };
private:
double calc_length()
{
// calculate length (here: dummy value)
return 1;
}
double calc_angle()
{
// calculate angle (here: dummy value)
return 0.5;
}
double length = 0;
double angle = 0;
}
;
class circle : public segment
{
public:
circle()
{
center.x = 0;
center.y = 0;
};
circle(const double r, const point c)
{
radius = r;
center.x = c.x;
center.y = c.y;
segment_id = 2;
};
~circle() {};
double get_radius() { return radius; };
point get_center() { return center; };
double get_length() { return 3.14 * radius; }; //returns circumference
private:
double radius = 0;
point center;
};
//-------------------------------------------------------
int main()
{
int nbr = 5;
point start;
start.x = 1;
start.y = 2;
point end;
end.x = 3;
end.y = 4;
point c;
c.x = 0;
c.y = 0;
double r = 9;
auto anotherCircle = std::make_unique<circle>(r, c);
auto anotherLine = std::make_unique<Line>(start, end);
std::unique_ptr<circle> yet_anotherCircle;
circle* myCircle = new circle(r, c);
Line* myLine = new Line(start, end);
//VERSION 1: Does not compile. I get an exception in <memory> line 1762 when trying to delete _Ptr
//std::vector<std::unique_ptr<segment>> v1;
//v1.emplace_back(anotherCircle);
//v1.emplace_back(anotherLine);
//std::cout << v1[0]->get_radius() << std::endl;
//v1.emplace_back(myLine);
//std::cout << v1[1]->segment_id << std::endl;
//VERSION 2: Compiles
std::vector<std::unique_ptr<segment>> v2;
v2.emplace_back(std::make_unique<circle>(r, c));
v2.emplace_back(std::make_unique<Line>(start, end));
}
The straight forward way that I imagine but that does not seem to work would require version 1 to work. I could then probably use template objects that I feed into the vector. Unfortunately this is not the way to go and I have not the slightest idea how to approach this. It would be awesome if somebody could help me here! Thanks!
You need to move items in vector, as your items are no copyable:
v1.emplace_back(std::move(anotherCircle));

How to write a template function that adds an object of variant class type to a vector?

I have another problem that I have no idea how to solve. Maybe somebody can help me.
What I want to do:
I have a vector that shall take elements of various class types. In my example code I have two classes (Line, circle) that are both derived from a virtual class segment.
My code shall chain several circle or Line elements and put them in the vector. Each element may be different from the other (different radii, different starting and ending points, etc) and the sequence of elements shall vary from execution to execution. That is for instance for the first execution I have a circle with radius 2 followed by another circle of radius 1, followed by a Line of length 4 and for the second execution I have a Line of length 1 followed by another Line of Length 5 in a different direction, followed by a circle of radius 0.5.
I've already learned how to compose the vector such that it can contain different types but as of now the sequence and definition of each element is hard-coded. Now I want to make this flexible (in the end the sequence and definition shall be file-driven). For this I attempt to implement a template function that takes whatever element is fed into it and adds it to the vector. The current definition also takes the vector as input but I may end up to define this function as a method for the vector.
Unfortunately I cannot figure out a way how to do it that works. I understand that I cannot copy a unique_ptr so I tried with the std::move() method but doesn't work. I get an C2664 error message of the xmemory module in line 671 saying that I cannot convert argument 1 in T2 into a std::nullptr_t.
Can somebody help me here? That'll be so awesome!
Here's my example code that implements the basic idea for my code:
#include <iostream>
#include <vector>
#include <variant>
struct point
{
double x;
double y;
};
class segment
{
public:
segment()
{
P1.x = 0;
P1.y = 0;
P2.x = 0;
P2.y = 0;
};
virtual ~segment() {};
virtual double get_radius() { return 0; };
virtual double get_length() { return 0; };
virtual double get_angle() { return 0; };
int segment_id = 0;
protected:
point P1;
point P2;
};
class Line : public segment
{
public:
Line() {};
Line(const point pt1, const point pt2)
{
P1.x = pt1.x;
P1.y = pt1.y;
P2.x = pt2.x;
P2.y = pt2.y;
segment_id = 1;
};
~Line() {};
double get_length() { return calc_length(); };
double get_angle() { return calc_angle(); };
private:
double calc_length()
{
// calculate length (here: dummy value)
return 1;
}
double calc_angle()
{
// calculate angle (here: dummy value)
return 0.5;
}
double length = 0;
double angle = 0;
}
;
class circle : public segment
{
public:
circle()
{
center.x = 0;
center.y = 0;
};
circle(const double r, const point c)
{
radius = r;
center.x = c.x;
center.y = c.y;
segment_id = 2;
};
~circle() {};
double get_radius() { return radius; };
point get_center() { return center; };
double get_length() { return 3.14 * radius; }; //returns circumference
private:
double radius = 0;
point center;
};
//-------------------------------------------------------
//T1: class type "segment", T2: class object Line or circle
template<typename T1, typename T2>
inline void add_segment(T1 v, T2 line_or_circle)
{
v.emplace_back(line_or_circle);
}
//-------------------------------------------------------
int main()
{
int nbr = 5;
point start;
start.x = 1;
start.y = 2;
point end;
end.x = 3;
end.y = 4;
point c;
c.x = 0;
c.y = 0;
double r = 9;
auto anotherCircle = std::make_unique<circle>(r, c);
auto anotherLine = std::make_unique<Line>(start, end);
circle myCircle(r, c);
//VERSION 1: Does now compile.
std::vector<std::unique_ptr<segment>> v1;
v1.emplace_back(std::move(anotherCircle));
v1.emplace_back(std::move(anotherLine));
std::cout << v1[0]->get_radius() << std::endl;
std::cout << v1[1]->segment_id << std::endl;
//VERSION 2: Compiles
std::vector<std::unique_ptr<segment>> v2;
v2.emplace_back(std::make_unique<circle>(r, c));
v2.emplace_back(std::make_unique<Line>(start, end));
//=================================================================
//now I want to implement this as a function call
//=================================================================
std::vector<std::unique_ptr<segment>> v3;
//VERSION 5:
auto myLine2 = std::make_unique<Line>(start, end);
add_segment(v3, std::move(myLine2)); //shall add object of class Line or circle (derived from virtual segment class, see above) to vector v3. In this example a Line but might be a circle
}
Your function add_segment is taking the vector by value. This fails to compile because the vector is uncopyable, as unique pointers are uncopyable. Even if you used a copyable pointer type, it would be a pointless method as the copy is destroyed at the end of the function.
You will also need to move the line_or_circle parameter in the body of add_segment.
template<typename T1, typename T2>
inline void add_segment(T1 & v, T2 line_or_circle)
{
v.emplace_back(std::move(line_or_circle));
}

Custom list.sort comparisons in C++

I have an std::list that I'm trying to sort based on some calculations. Point2D is a struct with only int no, double x, and double y;
Here's the method that contains my list.sort code:
std::vector<Point2D> GrahamScan::getSortedPointSet(std::vector<Point2D> points) {
Point2D lowest = getLowestPoint(points);
std::list<Point2D> list;
for (int i = 0; i < (int)points.size(); i++) {
list.push_back(points[i]);
}
list.sort(compare_points);
std::vector<Point2D> temp;
for (int i = 0; i < (int)list.size(); i++) {
temp.push_back(list.front());
list.pop_front();
}
return temp;
}
And here's the compare_points method I wrote:
bool GrahamScan::compare_points(const Point2D& a, const Point2D& b) {
if (a.x == b.x && a.y == b.y) {
return false;
}
double thetaA = atan2((long)a.y - lowest.y, (long)a.x - lowest.x);
double thetaB = atan2((long)b.y - lowest.y, (long)b.x - lowest.x);
if (thetaA < thetaB) {
return false;
}
else if (thetaA > thetaB) {
return true;
}
else {
double distanceA = sqrt((((long)lowest.x - a.x) * ((long)lowest.x - a.x)) +
(((long)lowest.y - a.y) * ((long)lowest.y - a.y)));
double distanceB = sqrt((((long)lowest.x - b.x) * ((long)lowest.x - b.x)) +
(((long)lowest.y - b.y) * ((long)lowest.y - b.y)));
if (distanceA < distanceB) {
return false;
}
else {
return true;
}
}
}
The error Visual Studio is spitting out at me is "GrahamScan::compare_points":non-standard syntax; use '&' to create a pointer to member"
I don't have much experience in C++, but I'm trying to convert some Java code that uses a TreeSet to C++ and this is my attempt.
Any assistance would be appreciated.
If you want to keep compare_points in GrahamScan namespace you need to make it static:
static bool GrahamScan::compare_points
The reason the compiler complains is that compare_points is a member function. It needs a GrahamScan object to be applied on. Behind the curtains the real function signature of compare_points is something like bool compare_points(GrahamScan *this, const Point2D& a, const Point2D& b). So either make it static or don't define it as a member function.
Once you make compare_points static, your lowest variable will no longer be accessible to it. Easier way to work around that is to make lowest also static:
class GrahamScan
{
// declaration is inside class
static Point2D lowest;
}
// definition is outside class
Point2D GrahamScan::lowest;
and use it like this:
std::vector<Point2D> GrahamScan::getSortedPointSet(std::vector<Point2D> points)
{
GrahamScan::lowest = getLowestPoint(points);
//...
}

How to move a point object on co-ordinates x-y in console - C++ OOP

I am doing my Object oriented programming assignment in which I am asked to create a game of catching numbers for children so that during their enjoyment they also learn counting numbers.
In here , I am supposed to create a Point class and an x-y coordinate. In here , I have to create a shift function which takes P (point object as a parameter). This function shift the first point when user presses key i.e arrow keys.
The problem is I am confused about what are the actual keywords use for arrow keys (like move UP, DOWN, LEFT, RIGHT) in c++ like we use in normal games to move an object or a person! ???
Here below is my code!
Class Point.h
#ifndef POINT_H
#define POINT_H
class Point
{
public:
Point(); // Default Constructor
Point(double, double, int); // Three argument constructor
void initialize(double, double, int);
void shift(Point p); // Shift the first point when user press keys
void setValue(int value);
int getValue() const;
void setX();
double getX() const;
void setY();
double gety() const;
void AddPointValue(Point p2); /*This function add the TWO points value
void displayPoint(); //This will use to display value of point
bool checkCoordinates();
bool checkTime(); // Check time remaining
private:
double x;
double y;
int value;
};
#endif
Implementation File
#include <iostream>
#include <windows.h>
#include "point.h"
using namespace std;
Point::Point() // Default Constructor
{
x = 0;
y = 0;
value = 0;
}
Point::Point(double x1, double y1, int value1){ // Three argument constructor
x = x1;
y = y1;
value = value1;
}
void Point::initialize(double init_x, double init_y, int init_value)
{
x = init_x;
y = init_y;
value = init_value;
}
void Point::shift(Point p){
if(p == VK_LEFT)
{
}else if(p == VK_RIGHT)
{
}else if(p == VK_UP)
{
}else if(p == VK_DOWN)
{
}
}
Its giving me an error right now that no match for an operator==(Operand type 'point' and 'int')
The issue with point and int is because you're trying to compare a 2d coordinate against an ASCII value (VK_*), change that part the following and it should be easier to maintain:
Point Point::shift(Point p, int keyPress)
{
Point maxSize = new Point();
Point minSize = new Point();
maxSize.x=80;
maxSize.y=40;
// Assuming a coordinate system of 0,0 (x,y) at top left of the display
switch (keyPress)
{
case (VK_LEFT): // increment the x coord by 1 to go left
p.x += 1;
if (p.x < minSize.x) p.x = minSize.x;
break;
case (VK_RIGHT): // decrement the x coord by 1 to go right
p.x -= 1;
if (p.x > maxize.x) p.x = maxSize.x;
break;
case (VK_UP): // decrement the y coord by 1 to go up
p.y -= 1;
if (p.y < minSize.y) p.y = minSize.y;
break;
case (VK_DOWN): // increment the y coord by 1 to go down
p.y += 1;
if (p.y > maxize.y) p.y = maxSize.y;
break;
}
return p;
}
you will also have to check that x and y are never smaller than 0 as that would take them off the display/cause an exception depending on how you structure the code and play area.
Hope this helps for your movement issues, but let me know if you need more info:)

Wrong version of overridden [] operator called in class

I have a simple two-dimensional line class which holds two vectors of doubles. I have added getValue and setValue functions, but would prefer the public interface to have the square bracket operator available alongside these functions. The following code shows the implementation and use:
#include <vector>
#include <algorithm>
#include <cassert>
class Simple2DLine
{
public:
Simple2DLine();
// Simple read method with linear interpolation
double getValue(double x) const;
// Simple write method, adds a curve point, keeping the arrays sorted
void setValue(double x, double y);
double& operator [](double x);
const double operator [](double x) const;
private:
std::vector<double> m_X;
std::vector<double> m_Y;
int getNearestIndex(double x) const;
};
Simple2DLine::Simple2DLine()
{
}
void Simple2DLine::setValue(double x, double y)
{
// Get the index of the point at or just before 'x'
int idx = getNearestIndex(x);
// Check if the exact point already exists.
if (idx >= 0)
{
if (m_X[idx] == x)
{
m_Y[idx] = y;
return;
}
else
{
// Insert adds the value just BEFORE idx, so increment it before inserting.
++idx;
m_X.insert(m_X.begin() + idx,x);
m_Y.insert(m_Y.begin() + idx,y);
return;
}
}
// Otherwise, just insert at the front.
m_X.insert(m_X.begin(),x);
m_Y.insert(m_Y.begin(),y);
}
double Simple2DLine::getValue(double x) const
{
// Make sure there are points - if not, return 0.
if (m_X.size() == 0)
{
return 0;
}
// Make sure it's not out of bounds.
if (x < m_X.front() || x > m_X.back())
{
return 0;
}
// Check if it's at or after the last point
if (x == m_X.back())
{
return m_X.back();
}
// Find the point just before the given point.
int idx = getNearestIndex(x);
// Check if we're on the exact point
if (m_X[idx] == x)
{
return m_X[idx];
}
else
{
// Find the distance from the nearest point and linearly interpolate.
double dist = x - m_X[idx];
return m_Y[idx] + dist * (m_Y[idx + 1] - m_Y[idx]) / (m_X[idx + 1] - m_X[idx]);
}
}
double& Simple2DLine::operator [](double x)
{
// Create a space for the new value
setValue(x,0.0);
int idx = getNearestIndex(x);
return m_Y[idx];
}
const double Simple2DLine::operator [](double x) const
{
return getValue(x);
}
// Returns the index of the point at or just before 'x'. Invalid values return -1.
int Simple2DLine::getNearestIndex(double x) const
{
if (m_X.empty())
{
return -1;
}
std::vector<double>::const_iterator xBegin(m_X.begin());
std::vector<double>::const_iterator xEnd(m_X.end());
// Get an iterator to the first value GREATER than our search value
std::vector<double>::const_iterator it = upper_bound(xBegin,xEnd,x);
// If the iterator is at the beginning, all values are greater
if (it == xBegin)
{
return -1;
}
// Otherwise, decrement the iterator by 1, and return its' distance from the start.
return (it - 1) - xBegin;
}
int main(int argc, char** argv)
{
Simple2DLine tda;
tda.setValue(0.0,10.0);
tda.setValue(1.0,15.0);
tda.setValue(2.0,20.0);
tda.setValue(3.0,25.0);
double tmp = tda.getValue(0.5);
assert(abs(tmp - 12.5) < 0.000001);
tmp = tda.getValue(1.5);
assert(abs(tmp - 17.5) < 0.000001);
tmp = tda.getValue(2.5);
assert(abs(tmp - 22.5) < 0.000001);
// Here, the wrong version of the overridden operator is being called.
tmp = tda[1.5];
tda[2.5] = 22.5;
}
When I access the line object in the following fashion, the correct version of the operator is called (non-const)
tda[2.5] = 22.5;
However, when I try to use the const version, as follows:
tmp = tda[1.5];
the non-const version is called. Is there an error in my implementation? Or is it not possible to access the class in this fashion?
The const version is called on const objects. So if you have an object declared like const Simple2DLine tda, const overloaded version of operator[] will be called.
Practically, you will see const objects as function parameters like:
void foo(const Simple2DLine& tda)
{
std::cout<< tda[0];
}
There you will notice const overloaded function being called.
Also your const overloaded operator[] can still return a reference.
Do you assume that automatically the const operator has to be called just because the expression containing it appears on the right side of an equation? This is not the way it works. The const version will be called if you have a const object.
You could e.g. try assigning the object to a const reference.
Simple2DLine const & tdaconst = tda;
tmp = tdaconst[1.5];
In the above code, the const version will be called.