Nested class: how to access the member variable in enclosed class - c++

The following code snippet aims to store all points in the member function mainFunc of enclosing class Solution in a priority_queue (i.e. pq), such that all points are in the order according to their distance to origin. However, the compiler reports an error:
error: invalid use of non-static data member 'Solution::ori'
Then I change the 3rd line of Point ori to static Point ori and change ori to Solution::ori in the function of distance(Point p), the link error occurs:
undefined reference to 'Solution::ori'
Could anyone help me on this? Thanks in advance!
/**
* Definition for a point.
* struct Point {
* int x;
* int y;
* Point() : x(0), y(0) {}
* Point(int a, int b) : x(a), y(b) {}
* };
*/
class Solution {
private:
Point ori;
class Comparator {
public:
// calculate the euclidean distance between p and ori
int distance(Point p) {
return pow(p.x-ori.x, 2) + pow(p.y-ori.y, 2);
}
// overload the comparator (), the nearest point to
// origin comes to the first
bool operator() (Point l, Point r) {
if (distance(l) > distance(r)) {
return true;
}
}
};
public:
/*
* #param points: a list of points
* #param origin: a point
*/
void mainFunc(vector<Point> points, Point origin) {
ori = origin;
priority_queue<Point, vector<Point>, Comparator> pq;
for (int i = 0; i < points.size(); i++) {
pq.push(points[i]);
}
}
};

You can modify your Comparator declaration to take a certain Point value in it's constructor:
class Solution {
private:
Point ori;
class Comparator {
public:
// Save the value in the functor class
Comparator(const Point& origin) : origin_(origin) {}
// calculate the euclidean distance between p and origin
int distance(Point p) {
return pow(p.x-origin_.x, 2) + pow(p.y-origin_.y, 2);
}
// overload the comparator (), the nearest point to
// origin comes to the first
bool operator() (Point l, Point r) {
if (distance(l) > distance(r)) {
return true;
}
}
private:
Point origin_;
};
public:
/*
* #param points: a list of points
* #param origin: a point
*/
void mainFunc(vector<Point> points, Point origin) {
ori = origin;
priority_queue<Point, vector<Point>> pq(Comparator(ori));
// ^^^^^^^^^^^^^^^
// Pass an instance of
// the functor class
for (int i = 0; i < points.size(); i++) {
pq.push(points[i]);
}
}
};

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

C++ Geometry hierarchy, Class upcasting and inheritance

I am working on a project for understanding classes and have hit a wall. If you have any advice about my syntax, please let me know where I am going wrong as I am still quite new to programming, but my question is to do with class inheritance. (A, C and D are included but pretty well completed).
My project:
A. Start with a point class... Override << (print values), +, - (to add and subtract point coordinates). I feel I have completed this portion.
B. Create a base class Shape. Shape will contain functions to calculate area, circumference and take point values to create a box that encapsulates the given shape. These will be overloaded by derived classes. Create a display() function that displays all relevant info (name, area, circumference and encapsulating box.
C. Build a heirarchy for shapes by making circle, square, triangle... add default and custom constructors whos arguments initialize the shapes using the correct number of point objects. I feel I have satisfied this too.
D. In main() Create an instance of each. Circle radius = to 23, square sides each = 25, Triangle sides = 10, 20 and 30 (very flat triangle, area = 0). Define each to contain the origin (0, 0). Display all the info. I feel I have completed this (minus the display function).
My question is (and where I am struggling), "How do I properly make/access functions from a base class (shape) to return meaningful information."
Do I literally just make them all virtual since some classes dont have the same information as others? (like Area() and Circumference()?)
#include <iostream>
#include <cmath>
using namespace std;
class Point {
public:
int x, y;
Point() {
x = 0;
y = 0;
}
Point(int x, int y): x(x), y(y) {} // constructor
friend ostream& operator<<(ostream& out, const Point number) { //Involves ostream to output the numbers
out << "(" << number.x << ", " << number.y << ")"; //that were input into the x and y values of Point.
return out;
}
friend Point operator+(Point first, Point second) { //Takes two mathematical vectors and tells the compiler
Point add; // to add the x values together and the y values together
add.x = first.x + second.x;
add.y = first.y + second.y;
return add;
}
friend Point operator-(Point first, Point second) { // same as above but with subtraction.
Point subtract;
subtract.x = first.x - second.x;
subtract.y = first.y - second.y;
return subtract;
}
};
class Shape {
protected:
float height, width;
public:
Shape() {
height = 0;
width = 0;
}
Shape(float h, float w) {
height = h;
width = w;
}
/*
int Display() {
//Do something..... Create a display function
return 0;
}
int BoundingBox() {
//Do something again......
return 0;
}
*/
virtual float Area() const = 0;
virtual float Circumference() const = 0;
virtual ~Shape() {};
};
class Circle: public Shape {
Point center;
float radius;
public:
Circle(): Shape() {};
Circle (Point p1, float r) { //Takes center point object, and given radius.
center = p1;
radius = r;
}
virtual float Area() const override { // Calculates circle area
return(M_PI * radius * radius);
}
virtual float Circumference() const override { // Calculates circumference
return(float (M_PI * 2 * radius));
}
virtual ~Circle() {};
};
class Square: public Shape {
Point first, second, third, fourth;
public:
Square(): Shape() {};
Square(Point p1, Point p2, Point p3, Point p4) { // Takes four point arguments and initializes them
first = p1;
second = p2;
third = p3;
fourth = p4;
height = second.x - first.x; //calculates the height and width from points
width = third.y - first.y;
}
virtual float Circumference() const override {
return 0; //Errors without the return statement
}
virtual float Area() const override{ // Calculates area by measuring the difference between given points
return(height * width);
}
virtual ~Square() {};
};
class Triangle: public Shape {
Point first, second, third;
public:
Triangle(): Shape() {};
Triangle(Point p1, Point p2, Point p3) { // Takes three point arguments and initializes them
first = p1;
second = p2;
third = p3;
height = third.y - first.y;// due to the nature of the question, this only works for flat triangles.
width = second.x - first.x;
}
virtual float Circumference() const override {
return 0; //Errors without the return statement
}
virtual float Area() const override {
return ((height * width) / 2);
}
virtual ~Triangle() {};
};
int main() {
Point p1(0, 0), p2(25, 0), p3(0, 25), p4(25, 25), p5(20, 0), p6(30, 0);
Circle c1 (p1, 23); // Circle with origin (0, 0) and a radius of 23
Square s1 (p1, p2, p3, p4); // Square with 4 points and the origin
Triangle t1 (p1, p5, p6); // Extraordinarily flat triangle with origin
cout << c1.Circumference() << endl;
cout << s1.Area() << endl;
cout << t1.Area() << endl;
}
At this point, I am feeling a bit lost of the woods and I am sure I have either created several mistakes along the way, or just a few, but regardless, I don't understand. Any advice would be appreciated!
edit: I have updated my code to include the recommendations to include virtual deconstructors, remove the getheight etc... statements, and add virtual to the derived functions
When you're working with inheritance, make sure to use a virtual destructor in all of your inherited classes, as well as the base class.
Your inherited virtual functions would benefit from being marked virtual and override too, in case you want to make further specializations.
You are overriding inherited functions, but then they do the same thing as the original, e.g. GetHeight(). That kinda defeats the point of inheriting those functions. They also do not need to be virtual if they aren't overridden.
Your derived classes would benefit from explicitly calling the base class's constructor. It will call the default constructor if you don't provide a specific constructor to call, which may or may not be the behaviour you intended - IMO it's safer to always provide the base class constructor you want!
As an example:
class Shape {
protected:
float height, width;
public:
Shape() {
height = 0;
width = 0;
}
Shape(float h, float w) {
height = h;
width = w;
}
virtual float Area() const = 0;
virtual float Circumference() const = 0;
virtual ~Shape() {};
};
class Circle: public Shape {
Point center;
float radius;
public:
Circle() : Shape() {};
Circle (Point p1, float r) : Shape() {
// Note you may wish to set the height and width here!
//Takes center point object, and given radius.
center = p1;
radius = r;
}
virtual float Area() const override { // Calculates circle area
return(M_PI * radius * radius);
}
virtual float Circumference() const override { // Calculates circumference
return(float (M_PI * 2 * radius));
}
virtual ~Circle() {};
};

How to construct base class multiple times in derived constructor

Hello I I have problem on my assignment which I need to init base constructor which is point multiple time in derived constructor which is polygon.
The polygon have at least 3 point , each point have a coordinate value. any one have ideas how to init base constructor multiple time in constructor init?
The inheritance ideas is not my ideas , is the assignment question.
this is the question
Polygon  (constructor) creates a polygon with npoints vertices, the vertices take their values from those stored in the array points. Note that the array points should not be assumed to persist; it may be deleted after the constructor is invoked.
struct PointType
{
float x;
float y;
};
class Point
{
public:
Point(const PointType& center );
virtual ~Point();
private:
PointType m_center;
};
class Polygon : public Point
{
public:
Polygon(const PointType* points, int npoints);
~Polygon();
const VectorType& operator[](int index) const;
private:
int m_npoints;
Object::PointType * m_pt;
};
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include "Object.hpp"
using namespace std;
const float eps = 1e-5f;
bool Near(float x, float y)
{
return abs(x-y) < eps;
}
float frand()
{
return 10.0f*float(rand())/float(RAND_MAX);
}
int main()
{
srand(unsigned(time(0)));
int count = 0,
max_count = 0;
// Polygon tests
int n = 3 + rand()%8;
float *xs = new float[n],
*ys = new float[n];
float x = 0, y = 0;
PointType *Ps = new PointType[n];
for (int i=0; i < n; ++i) {
xs[i] = frand(), ys[i] = frand();
Ps[i] = PointType(xs[i],ys[i]);
x += xs[i], y += ys[i];
}
}
Point::Point(const PointType& center)
: m_center{center}
{
}
// this is wrong, can correct me how to construct it?
Polygon::Polygon(const PointType* points, int npoints, float depth)
:m_npoints{npoints} , m_pt{new Object::PointType[npoints]}, Point (*m_pt ,depth)
{
for(int i=0; i < m_npoints ; ++i)
{
m_pt[i] = points[i];
}
}
enter code here
this the assignment structure like
enter image description here
I took away other object class implementation
Your assignment text doesn't say anything about inheritance. It essentially describes composition. Go from here:
class Polygon
{
public:
// constructor should allocate the array
Polygon(const PointType* points, int npoints);
~Polygon();
private:
Point *m_npoints; // or use smart pointer if you're allowed to.
};
It is a trick question, is actually want me to find centroid point of polygon.
So I need a private compute center point of polygon function and return the result of center point of polygon, and then call the function in point constructor when init.

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.