Wrong version of overridden [] operator called in class - c++

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.

Related

Is there a way to explicitly call optional arguments in c++?

When I create a function such as:
int addThree(int x=1, int y=1, int z=1)
I want to call the function such that it uses the default arguments for x and z, but not y.
Some attempts have been addThree(5,,5) and addThree(5,NULL,5), but neither work effectively.
The default arguments must be at the last of your list, so do as follows
int addThree(int y , int x = 1, int z = 1)
{
//some stuff
return someInt;
}
, hence you can call it as
int ans = addThree(4);
Default arguments in C++, need to be specified in immediate succession, and cannot be succeeded by a non-default parameter.
So, something like
int sum(int x = 0, int y, int z = 0) {
return (x + y + z);
}
is forbidden in C++
The function needs to be as follows:
#include <iostream>
int sum(int x, int y = 0, int z = 0) {
return (x + y + z);
}
int main() {
std::cout << sum(1) << "\n";//calls sum(1,0,0)
std::cout << sum(1,2) << "\n";//calls sum(1,2,0)
return 0;
}
However, while specifying default arguments, you always need to take care in function overloading. The overloaded functions cannot be called ambiguously..
So a code like:
#include <iostream>
int sum(int x, int y = 0, int z = 0) {
return (x + y + z);
}
float sum(int x, float y = 0.0, float z = 0.0) {
return (float(x) + y + z);
}
int main() {
std::cout << sum(1) << "\n";
return 0;
}
does not compile and righty produces ambiguity error, as the compiler does not understand
Whether it should call the first sum, or the second sum.
If you're consistently passing a value for one parameter and using the defaults for the others, you can rearrange the parameters to the one you need to pass is first, and the ones for which you use defaults come later. But that only works if it's essentially always the same ones for which you supply a value vs. use the defaults.
Otherwise, if you need something similar to the basic capability badly enough, you can pass an instance of a class, and have that class implement the named parameter idiom.
class triplet {
int x_ {1};
int y_ {1};
int z_ {1};
public:
triplet &x(int val) { x_ = val; return *this; }
triplet &y(int val) { y_ = val; return *this; }
triplet &z(int val) { z_ = val; return *this; }
int x() const { return x_; }
int y() const { return y_; }
int z() const { return z_; }
};
int addThree(triplet const &t) {
return oldAddThree(t.x(), t.y(), t.z());
}
int ans = addThree(triplet().x(4));
This lets you use the defaults for as many or few of the values you need as you want, and override only those that you actually want to. On the other hand, it does add a fair amount of syntactic overhead, so you have to want the capability pretty badly to bother.

Unexpected output zero

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);
}

Members of derived inner classes

Goal
I am working on implementing an IntegerRing, which is a structure in abstract algebra. This type of ring is an Abelian group (something that I have already implemented) under addition. Rings are equipped with two operators, + and *.
Choice of implementation
For this reason, I have decided to define IntegerGroup as class that has GroupElements that have the operators. The complete, working code for that is found below:
IntegerGroup.h
#ifndef DATAGROUP_H
#define DATAGROUP_H
#include "Array.h"
#include <iostream>
// This group is the integers mod n
// multiplication in integer group is simply integer addition modulo n
class IntegerGroup
{
public:
IntegerGroup();
IntegerGroup(int);
class GroupElement
{
int m;
IntegerGroup* group;
public:
GroupElement();
GroupElement(int, IntegerGroup*);
~GroupElement();
GroupElement operator*(const GroupElement&);
GroupElement operator*=(const GroupElement&);
bool operator==(const GroupElement&);
bool operator!=(const GroupElement&);
int val() const;
friend std::ostream& operator<<(std::ostream& o, const GroupElement& e)
{
return (o << e.m);
}
};
GroupElement identity() const;
int size() const;
friend std::ostream& operator<<(std::ostream& o, const IntegerGroup& g)
{
return (o << g.elements);
}
private:
int n;
//GroupElement * identity;
Array<GroupElement> elements;
void createNewElement(int);
};
#endif
IntegerGroup.cpp
#include "IntegerGroup.h"
#include <new>
#include <iostream>
IntegerGroup::IntegerGroup()
{
}
IntegerGroup::IntegerGroup(int n)
: n(n), elements(Array<IntegerGroup::GroupElement>(n))
{
//this is to have integers in [0,n-1]
for (int j = 0; j < n; j++)
{
this->createNewElement(j);
}
}
void IntegerGroup::createNewElement(int m)
{
// create new GroupElement
GroupElement newElement(m, this);
// store it at index m in elements
this->elements[m] = newElement;
}
IntegerGroup::GroupElement::GroupElement()
: group(0)
{
}
IntegerGroup::GroupElement::GroupElement(int m, IntegerGroup * g)
: group(g)
{
// this->m must be in [0, g->size() - 1]
this->m = m % g->size();
if (this->m < 0) this->m = g->size() + this->m;
}
IntegerGroup::GroupElement::~GroupElement()
{
if (this->group)
{
this->group = 0;
}
}
IntegerGroup::GroupElement IntegerGroup::identity() const
{
// IntegerGroup consists of all integers in [0, n-1], and identity is 0
return this->elements[0];
}
// this group is simply the integers mod n, and should be populated integers in [0,n-1]
// thus, multiplication is simply a matter of returning the element at index (a+b)%n
IntegerGroup::GroupElement IntegerGroup::GroupElement::operator*(const IntegerGroup::GroupElement& b)
{
// if the group is not defined
if (!this->group)
// we simply perform integer multiplication
return GroupElement(this->val() * b.val());
// otherwise, perform group multiplication
return GroupElement((this->val() + b.val()) % this->group->size());
}
IntegerGroup::GroupElement IntegerGroup::GroupElement::operator*=(const IntegerGroup::GroupElement& b)
{
return ((*this) = (*this) * b);
}
bool IntegerGroup::GroupElement::operator==(const IntegerGroup::GroupElement& b)
{
return this->m == b.m;
}
bool IntegerGroup::GroupElement::operator!=(const IntegerGroup::GroupElement& b)
{
return !(*this == b);
}
int IntegerGroup::GroupElement::val() const { return this->m; }
int IntegerGroup::size() const { return this->n; }
Array.cpp, Array.h are merely templated wrapper classes. The code to that is also already working. You can find the files for them on GitHub here, or you could use std::vector instead. (It just now occurred to me that right now, I could do that.)
The problem
When I tried creating IntegerRing, and compiling, I got a myriad of bizarre errors, most of which had to do with the class's own functions using private class data.
Here is my implementation thus far of IntegerRing:
IntegerRing.h
#ifndef INTEGERRING_H
#define INTEGERRING_H
#include "IntegerGroup.h"
#include "Operators.h"
class IntegerRing : public IntegerGroup
{
public:
class Element : public IntegerGroup::GroupElement
{
public:
using IntegerGroup::GroupElement;
/*Element();
Element(int);
Element(int, IntegerRing*);
~Element();*/
operator IntegerGroup::GroupElement() { return IntegerGroup::GroupElement(); }
Element(const IntegerGroup::GroupElement& el)
{
// copy everything from el into *this
this->m = el.m;
this->group = el.group;
}
/*Element operator+(const Element&);
Element operator-(const Element&);
Element operator*(const Element&);
Element operator+=(const Element&);
Element operator-=(const Element&);
Element operator*=(const Element&);*/
};
Element identity(Operators);
private:
};
#endif
IntegerRing.cpp
#include "IntegerRing.h"
#include "IntegerGroup.h"
#include "Operators.h"
/*IntegerRing::Element::Element()
{
}*/
/*IntegerRing::Element(const IntegerGroup::GroupElement& el)
{
// copy everything from el into *this
this->m = el.m;
this->group = el.group;
}
/*
IntegerRing::Element IntegerRing::Element::operator+(const IntegerRing::Element& b)
{
// IntegerRing is simply Abelian group under addition
// thus, we treat the elements like group elements first, multiply under that group, and cast to ring elements
return (IntegerRing::Element)(((IntegerGroup::GroupElement)(*this)) * ((IntegerGroup::GroupElement)b));
}
IntegerRing::Element IntegerRing::Element::operator-(const IntegerRing::Element& b)
{
int val;
// if this has a group
if (this->group)
{
// compute (this->m - b.m) % this->group->size()
val = (this->m - b.m) % this->group->size();
// if that value is negative, add this->group->size() to it
if (val < 0) val = this->group->size() + val;
}
// otherwise, val is simply the integer difference of this->m,b.m
else val = this->m - b.m;
// return element with this value
return Element(val);
}
IntegerRing::Element IntegerRing::Element::operator*(const IntegerRing::Element& b)
{
if (this->group)
return IntegerRing::Element((this->m - b.m) % this->group->size());
return IntegerRing::Element(this->m - b.m);
}
IntegerRing::Element IntegerRing::Element::operator+=(const IntegerRing::Element& b)
{
return ((*this) = (*this) + b);
}
IntegerRing::Element IntegerRing::Element::operator-=(const IntegerRing::Element& b)
{
return ((*this) = (*this) - b);
}
IntegerRing::Element IntegerRing::Element::operator*=(const IntegerRing::Element& b)
{
return ((*this) = (*this) * b);
}
*/
IntegerRing::Element IntegerRing::identity(Operators op)
{
// if op is ADDITIVE
if (op == ADDITIVE)
// return what the base version of this method would return
return (IntegerRing::Element)(((IntegerGroup::GroupElement*)this)->identity());
// multiplicative identity requested, and it is 1
return (IntegerRing::Element)this->elements[0];
}
Operators.h
#ifndef OPERATORS_H
#define OPERATORS_H
enum Operators
{
ADDITIVE, MULTIPLICATIVE
};
#endif
The compiler thinks the copy constructor for IntegerRing::Element is really a function that returns an int.
Screenshot of errors
Here is screenshot of errors:
How do I resolve all this?
The reason is that you can't access class's private fields.
Inheritance/Nested Class do not change this.(Exception is inner class can always access it's enclosing class's any member(since C++11))
For the first error in log using IntegerGroup::GroupElement; should be usingIntegerGroup::GroupElement::GroupElement; inside IntegerRing::Element, by the way, I don't see the need of this class.
Turns out that my years of not using C++ for serious OOP like this has caused me to forget things. First of which: derived classes have access to protected,public members, and not private unless you declare derived class a friend in base class.
Second: how to write copy constructors. Sadly, derived classes have access to their own inherited protected data members, not base class's. To remedy this, I just write copy constructor like this:
IntegerRing::Element::Element(const IntegerGroup::GroupElement::GroupElement& el)
: IntegerGroup::GroupElement(el)
{
}

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);
//...
}

Returning a class object based on two variables C++

I need help with a problem pertaining to classes. I know how to solve it but I am wondering if there is a better solution than my current idea.
Each Class Tile Object and Class Player Object has an x and y position. I would like to know if there is a way to expedite things. My current idea is if-else statements like this:
if(x==1) {
if(y==1) {
return tileone1;
} else if(y==2) {
return tileone2;
} else if(y==3) {
return tileone3;
} else if(y==4) {
return tileone4;
} else if(y==5) {
return tileone5;
} //......
} else if(x==2) {
if(y==1) {
return tiletwo1;
} else if(y==2) {
return tiletwo2;
} else if(y==3) {
return tiletwo3;
} else if(y==4) {
return tiletwo4;
} else if(y==5) {
return tiletwo5;
} //......
} //......
The problem is it would take way too long to write this for every tile.
I need a function that will return a Tile object based on the x and y input of the Object Player. Any other solution would be great as well.
Tile getTileBasedOnCoords(int x, int y){
}
There are multiple ways to achieve this. The easiest seems to be (given the question) is by putting all Tile objects into the array, and returning the one with corresponding index.
Use a map with custom keys providing x and y values. This way you have direct access to the tile without the need to compare each tile with the player position (see getSectorByCoordinate() in the following code taken from a project of mine).
struct CSectorCoordinate
{
private:
int mX;
int mY;
public:
CSectorCoordinate();
CSectorCoordinate(int aX, int aY);
bool operator() (const CSectorCoordinate & a, const CSectorCoordinate & b) const;
int getX();
int getY();
};
...
bool CSectorCoordinate::operator() (const CSectorCoordinate & a, const CSectorCoordinate & b) const
{
// note: the following conditions ensure a strict weak ordering (see documentation of std::map)
if (a.mX < b.mX)
return true;
if (b.mX < a.mX)
return false;
return a.mY < b.mY;
}
...
typedef std::map<CSectorCoordinate, Configuration::CSectorEntity *, CSectorCoordinate> CSectorCoordinateMap;
CSectorCoordinateMap mSectorCoordinateMap;
...
bool CSectorEntityConfigurationBunch::getSectorByCoordinate(int aX, int aY, Configuration::CSectorEntity * & prSector)
{
CSectorCoordinateMap::const_iterator i(mSectorCoordinateMap.find(CSectorCoordinate(aX, aY)));
if (i != mSectorCoordinateMap.end())
prSector = i->second;
else
prSector = 0;
return prSector;
}