Losing Vector Contents Outside of the Constructor - c++

I'm relatively new to C++ and have been trying to troubleshoot this problem for awhile now, but can't figure this out. I have 2 classes, one called Polygon and one called Rectangle. Rectangle is a child class of Polygon. Polygon contains a std::vector<Points> called _points.
I would like my Rectangle constructor to add some Points to _points based on the constructor arguments. That sounded simple enough. However, when I add Points to _points, they seem to get lost outside of the constructor. When I check the size of _points inside the constructor, it gives the right value. However, when I check it back in the main program, right after constructing the Rectangle, it is 0. I think there is something going on under the hood I don't know about. Any ideas on what could be wrong?
Here's some snippets of code I think may help
Polygon.cpp
// This is just for reference, there are a few other classes involved
// but I don't think they should effect this.
Polygon::Polygon()
: Object()
, _lastColor(0,0,0)
, _lastDotColor(.5, .5, .5)
{
_points = vector<Point>();
_colors = vector<RGB>();
_dotColors = vector<RGB>();
_numDotSections = -1;
}
Rectangle.cpp
Rectangle::Rectangle(Point p1, Point p2, RGB lineColor, double dotSeg, RGB dotColor) : Polygon(){
_points.push_back(p1);
// Prints out 1
std::cout << "Point size: " << getPoints() << std::endl;
}
Driver.cpp
Rectangle playerPolygon = Rectangle(Point(1,1,-.75), Point(-1,-1,-.75), RGB(1,1,1));
// Prints 0
cout << "Number of points (Rectangle): " << playerPolygon.getPoints() << endl;
Edit1: Per request, here's the majority of the text for Polygon.cpp
// File imports
#include <GL/glut.h>
#include <iostream>
#include <math.h>
#include "Polygon.h"
using namespace std;
/**
* Default constructor for Polygon. Uses initializer lists
* to setup the different attributes
*/
Polygon::Polygon()
: _lastColor(0,0,0)
, _lastDotColor(.5, .5, .5)
, _numDotSections(-1)
{
}
/**
* Transforms the points of the polygon and draws it on the screen
*
* #param currentWorld a reference to the world the object is in
*/
void Polygon::draw(World* currentWorld){
// Some long and overly complicated method that should not apply here
}
/**
* Adds a point to the polygon
*
* #param point the point to be added
* #param color the color to start at this point
* #param dotColor the dotted line color to start at this point
*/
void Polygon::addPoint(Point point, RGB color, RGB dotColor){
// Add the values to the lists
_points.push_back(point);
_colors.push_back(color);
_dotColors.push_back(dotColor);
// Update the last colors
_lastColor = color;
_lastDotColor = dotColor;
}
/**
* Adds a point to the polygon
*
* #param point the point to be added
* #param color the color to start at this point
*/
void Polygon::addPoint(Point point, RGB color){
// Add the point using the last dotted line color
addPoint(point, color, _lastDotColor);
}
/**
* Adds a point to the polygon
*
* #param point the point to be added
*/
void Polygon::addPoint(Point point){
// Add the point using the last line and dotted line color
addPoint(point, _lastColor, _lastDotColor);
}
/**
* Set the color of the current line
*
* #param color the color of the line to be added
*/
void Polygon::setColor(RGB color){
// Add the color to the list
_colors.back() = color;
// Update the last used color
_lastColor = color;
}
/**
* Set the dotted line color of the current line
*
* #param color the dotted line color to be added
*/
void Polygon::setDotColor(RGB color){
// Add the dotted line color to the list
_dotColors.back() = color;
// Update the last used dotted line color
_lastDotColor = color;
}
/**
* Sets the number of dotted sections for the current shape
*
* #param number the number of dotted sections
*/
void Polygon::setDotSections(int number){
_numDotSections = number;
}
// I just put this in to see if the issue was copying, but this text is never output
// so I don't believe it's being called
Polygon::Polygon(const Polygon& rhs){
std::cout << "Polygon copied" << std::endl;
std::cout << "RHS: " << rhs._points.size() << " LHS: " << getPoints() << std::endl;
}
int Polygon::getPoints(){
return _points.size();
}

I don't see a reason. But I strongly suggest that you delete some lines in the constructors for copying objects. Also, the default constructor is not necessary to be in the constructor initialization list.
// This is just for reference, there are a few other classes involved
// but I don't think they should effect this.
Polygon::Polygon()
: _lastColor(0,0,0)
, _lastDotColor(.5, .5, .5)
, _numDotSections(-1)
{
}
How do you implement getPoints()?

Rectangle playerPolygon = Rectangle(...);
You're invoking the copy constructor here. Did you write a copy constructor? Is it copying _points? If not, that's a bug; and there's really no need to force another copy constructor call in any case. Why not just
Rectangle playerPolygon(...);
? (But do watch out for the vexing parse...)

After sleeping on it, I figured it out! Being used to Java, I had made what I thought were overloaded constructors:
Rectangle::Rectangle(Point p1, Point p2, RGB lineColor, double dotSeg, RGB dotColor) : Polygon(){
// Add some points here
}
Rectangle::Rectangle(Point p1, Point p2){
// Supposed to call the first constructor
Rectangle(p1, p2, RGB(), -1, RGB());
}
Rectangle::Rectangle(Point p1, Point p2, RGB lineColor){
// Supposed to call the first constructor
Rectangle(p1, p2, lineColor, -1, lineColor);
}
But then I tried using the main constructor in my program and it worked! After doing a bit of research, it turns out that constructors cannot be overloaded like this. When a constructor other than the original one is called, it creates a new Rectangle with the points, then destructs it right away because it's not set equal to anything and returns a new rectangle without the points.
I found the easiest way around this is to use default parameters, so I have the same functionality
Rectangle(Point p1, Point p2, RGB lineColor = RGB(), double dotSeg = -1, RGB dotColor = RGB());
I suppose this would have been caught if I put the entire code in there right away, but thanks for all the help and suggestions!

A wild guess: Rectangle inherits from Polygon, and the Rectangle class declares a second member variable named _points that hides the base class version. Rectangle's constructor then adds some elements to Rectangle::_points, and some other function later checks the size of Polygon::_points and finds none.
If this is the case, just take away the declaration of _points in Rectangle. It needs to use the base class version, either directly if Polygon::_points is accessible (public or protected), or via accessor functions.

A few hints that don't answer your question, but nonetheless:
I'm not sure why you derive Rectangle from Polygon. Unless you plan on taking advantage of polymorphism with the two types then it's not necessary and can even lead to incorrect code. The same holds for deriving Polygon from Object.
Don't use names that start with an underscore. The standard reserves this sort of names for implementors.
There's no need to explicitly initialize members with their default values. The compiler does that for you. For example, the statement _points = vector<Point>(); in the default Polygon constructor is redundant. Also, the call to the default constructor of Object() in that same Polygon constructor is redundant.

Related

Assign a point to the class member

i trying to implement the following link http://in.mathworks.com/help/vision/examples/motion-based-multiple-object-tracking.html in opencv and c++.
I have created a class say ex:
class assign
{
vector <int> id;
vector <int> area;
vector<Point> centroid;
};
After this i have created an object
assign id;
Now i want to assign the centroid value and other values too. what i tried is
id.centroid (p);
where p is a "point" But i'm getting error for this. I don't know where i'm going wrong.
centroid is a private member of class assign. If you want to access it directly, you should make it public
class assign
{
public:
vector<Point> centroid;
//...
};
And if you want to add a Point into centroid, you should
id.centroid.push_back(p);
The main answer is already given by songyuanyao. What I want to add is a possible solution which allows you to use the member variables like you already tried it.
If you want to get and set the member centroid with id.centroid(p) you could go with the following class declaration:
class Assign
{
public:
vector<Point> centroid();
void centroid(vector<Point> c);
private:
vector<Point> m_centroid;
};
The definition might then look like this:
// getter
vector<Point> Assign::centroid() {
return m_centroid;
}
// setter
void Assign::centroid(vector<Point> c) {
m_centroid = c;
}
Now if you use id.centroid(p) to set the member the overloaded setter will be called and will set the variable. If you call p = id.centroid() (empty parameter list) the overloaded getter will be called and will return the current m_centroid.
To add to the previous answers; if you want to expand on your class this can be done for you during construction of your object.
class Assign {
private:
std::vector<int> m_vIds;
std::vector<int> m_vAreas;
std::vector<Vec2> m_vCentroids;
public:
Assign(); // Default Constructor Same As What You Have But Not Declared.
Assign( int* pIds, int* pAreas, int* pCentroids ); // Create By Using Pointers
// Create By Passing In Either Pre Filled Vectors Or Even An Empty
// Vectors To Be Filled Out Later. Passes By Reference. This Will
// Also Set The Variables That Are Passed In From The Caller.
Assign( std::vector<int>& vIds, std::vector<int>& vAreas, std::vector<Vec2>& vCentroids );
// Since You Are Using Vectors Within This Class It Is Also Good To
// Have A Destructor To Clear These Out Once The Object Is Done And
// Ready To Be Destroyed Or Removed From Memory
~Assign();
};
// The Destructor Would Look Like This
Assign::~Asign() {
if ( !m_vIds.empty() ) {
m_vIds.clear();
}
if ( !m_vAreas.empty() ) {
m_vAreas.clear();
}
if ( !m_vCentroids.empty() ) {
m_vCentroids.empty();
}
} // ~Assign
// NOTE: I used Vec2 instead of point due to my use of programming
// 2D & 3D Graphics Rendering Engines; Most Graphics APIs and Libraries
// along with Most Math Libraries Will Not Have A Point Class; Most Will
// Use Vec2 or Vec3 - Vector2 or Vector3 & Vector4 Since in terms of
// memory they are exactly the same thing. It is up to you to know which
// objects are points or locations, and which are vectors as in forces,
// velocities, accelerations, directions, normals etc. The only major
// difference between a discrete Point Class or Structure versus a Vector
// Class is that the Vector Class usually has operations defined with it
// to do vector mathematics such as addition, subtraction, multiplication by
// value, multiplication by vector, division by value, division by vector,
// cross & dot product, comparisons, testing if vector is 0, setting it to
// be a normal vector, returning the magnitude or length and a few others.
// The general point class or object is usually just data values or
// simply coordinates without operations.

upcasting and downcasting c++

I was playing around with pointer to the base class, and I casted a rectangle pointer into a circle pointer and called the printradius() function from the rectangle! Could someone explain why this is allowed? Thanks.
#include <iostream>
#include <string>
using namespace std;
class Shape {
};
class Circle: public Shape {
private:
double radius;
public:
Circle(double r)
{ radius = r;}
void printradius()
{ cout << "circle's radius is " << radius << endl;}
};
class Rectangle: public Shape {
private:
double width, length;
public:
Rectangle(double l, double w)
{ length = l; width = w;}
};
int main() {
Rectangle r( 2.0, 2.0); // only a rectangle is created
Shape* s = &r; // up cast into a shape
Circle* c = static_cast<Circle*>(s); //down cast into a circle
c->printradius();
}
output:
circle's radius is 2
What do you mean by "allowed"?
The language explicitly states that the result of such static_cast is undefined, so it is not really "allowed" in this case. In order to perform a valid downcast from Shape * to Circle *, you have to ensure that Shape * actually points to Circle or something derived from Circle. Otherwise, the behavior is undefined.
As for why the compiler did not catch it... The compiler cannot possibly catch errors that depend on run-time conditions. In general case the compiler does not know what your s pointer actually points to.
As for why the language even offers such feature... It offers it because it can be extremely useful when one uses it properly.
The static cast is "because I said so.", in other words, trust me, the programmer, that the thing is what I say it is, a circle pointer in this case. When calling the printradius() method, The this pointer is for r, and when printradius() happens to deref looking for a radius, it finds that first double, with a value of 2.0. There is no crash, or reported error from running this way, but as you know, it makes no sense.
Use a dynamic cast and check the value returned. You will see null, because rectangle and circle are not the same.

Class attribute incorrect value C++

EDIT: To initialize the position array m_pos[3] I set all it's values to 0 in the constructor and then I call from the main function another function called SetPos() which only sets the position of the planet in the 3D map:
void SetPos(float x, float z);
void Planet::SetPos(float x, float z)
{
m_pos[0]=x;
m_pos[1]=0;
m_pos[2]=y;
}
Thus, the constructor takes the form:
Planet::Planet()
{
m_pos[0]=0;
m_pos[1]=0;
m_pos[2]=0;
}
Is that a bad way to do it? (by need, i can't set the position directly through the constructor).
ORIGINAL:
I've created a class called Planet which controles a series of planets (Planet object) in a map. Each object has an array pos[3] which stores the coordinates where the planet must be drawn.
The planets also own a function called DrawConnections() which is in charge of drawing lines representing the connections between the actual planet and the other planets. The planets that one planet is connected to are stored in a vector, std::vector<Planet> connections.
Since attributes are encapsulated, there's a function in the Planet class which returns the position of the planet, called GetPos(float* pos), where *pos is a pointer to an array capable of storing the position of the planet.
First things first, those are the prototypes and variable declarations from Planet.h file:
public:
void DrawConnections(float radius);
void GetPos(float* position);
private:
float m_pos[3];
std::vector<Planet> m_connection;
The function DrawConnections() from Planet.cpp looks like this:
void Planet::DrawConnections(float radius) //parameter radius controls width of lines
{
float position[3]={0.0f,0.0f,0.0f}; //array storing the position of the planets
//which we are connecting to
//various OpenGl calls go here
glBegin(GL_LINES); //begins drawing the lines
for(int i=0;i<m_connection.size();i++) //for each planet we are connected to, draw a
//line
{
glVertex3f(m_pos[0],m_pos[1],m_pos[2]); //draws the first point of the line in the
//actual planet
m_connection[i].GetPos(position); //Gets the position of the planet we connect to
glVertex3f(position[0],position[1],position[2]); //draws the second point of the
//in the planet we connect to
}
glEnd(); //ends drawing
//some other OpenGl calls
}
The function GetPos() from Planet.cpp looks like this:
void Planet::GetPos(float* position)
{
position[0]=m_pos[0]; //copies the data from the position array to
position[1]=m_pos[1]; //the given pointer
position[2]=m_pos[2];
}
Any planet has x, neither z, 0 coordinate. Each one of them has a set of (x,y,z) coordinates, with x and z always different to 0.
However, some of the calls to GetPos() return x and z equal to 0, while others work properly.
This results in many lines going from the planets to the bottom left corner of the screen, without representing any connection. From what I've figured out I think the problem is in the GetPos(). However, other similar drawing functions also use GetPos() and work perfectly when they're called before the DrawConnection() function, but seem to be affected when they're called once DrawConnections() has been called It is as if that one was modifying the values of the position array when called and thus disturbing everything else which has to be with the position, including herself.
As an additional information, I'm working with Codeblocks and the MinGW GNU GCC compiler. I appreciate any help that you could give me.
Why not do?
public:
void DrawConnections(float radius);
const std::vector<float>& GetPos() const {return m_pos;};
private:
std::vector<float> m_pos;
std::vector<Planet> m_connection;

Static C++ variable, without default constructor, loses value

I have a class with a static variable. Since I need a constructor that isn't the default, I'm getting a little confused, but I hope I did it well
Class
class Object3D{
public:
static Object3D ObjControl;
Object3D(); //this is here just for the initialization of the static variable
Object3D(Triangle *mesh);
Triangle *mesh;
};
At this point I need to create an Object3D and I do as below
bool Engine::OnInit() {
if(SDL_Init(SDL_INIT_EVERYTHING) < 0) {
return false;
}
if((Surf_Display = SDL_SetVideoMode(WIDTH, HEIGTH, BBP, FLAGS)) == NULL) {
return false;
}
arma::colvec::fixed<3> upDirection;
upDirection << 0 << 1 << 0;
Camera cam(0.0, 0.0, 10.0, 10.0, 200.0, 90.0, upDirection);
Camera::CameraControl = cam;
arma::colvec::fixed<3> vertexA;
vertexA << -1 << 1 << 0;
arma::colvec::fixed<3> vertexB;
vertexB << 1 << 1 << 0;
arma::colvec::fixed<3> vertexC;
vertexC << 0 << -1 << 0;
Triangle tri(vertexA, vertexB, vertexC);
Triangle mesh[1];
mesh[0] = tri;
Object3D obj(mesh);
Object3D::ObjControl = obj; // PROBLEM! -> when the function extis from the OnInit ObjControl doesn't have anything inside.. it is like cleaned at the exit
return true;
}
The problem is the one that is inserted in the comment before the return.
Then when I need to pass that object to the rendering function, as below; the application closes because I'm trying to access to a location of memory not initialized
void Engine::OnRender(){
Rendering.WfRender(Object3D::ObjControl, Surf_Display, 1);
}
I think I'm doing something wrong with the static variable, but I did the same with a static variable for a Camera class, as you can see in the Engine::OnInit, and there everything works well. So I have no clue what's going on.
The main issue in your program is that you make a Triangle instance (mesh) in your function and that you pass a pointer to your static member variable ObjControl. When you leave the function, mesh is no longer available, so ObjControl points to an invalid instance. This could be solved by storing an actual Triangle instead of a pointer to a Triangle in Object3D or a container of Triangles if more are needed.
Does your Object3D class only hold onto the pointer to the mesh or take a copy of it?
Does it implement a deep-copy copy constructor?
I ask because your mesh is going out of scope after being assigned to obj, and obj is going out of scope after being assigned to the static variable. You need to either assign the mesh on the heap and hand that pointer to the static variable, or ensure the actual data is copied by correctly implementing the right constructors.
EDIT: Or, as this looks like games development, get it done quick and nasty! ;-)
Object3D::ObjControl.mesh = new Triangle(vertexA, vertexB, vertexC);
...and lose the local variables tri, mesh, and obj.

C++ pass by pointer

Guys, I am very new to c++. I have just wrote this class:
class planet
{
public:
float angularSpeed;
float angle;
};
Here is a function trying to modify the angle of the object:
void foo(planet* p)
{
p->angle = p->angle + p->angularSpeed;
}
planet* bar = new planet();
bar->angularSpeed = 1;
bar->angle = 2;
foo(bar);
It seem that the angle in bar didn't change at all.
Note that you are passing bar by pointer, not by reference. Pass-by-reference would look like this:
void foo(planet& p) // note: & instead of *
{
p.angle += p.angularSpeed; // note: . instead of ->
}
Pass-by-reference has the added benefit that p cannot be a null reference. Therefore, your function can no longer cause any null dereferencing error.
Second, and that's a detail, if your planet contains only public member variables, you could just as well declare it struct (where the default accessibility is public).
PS: As far as I can see it, your code should work; at least the parts you showed us.
Appearances must be deceptive because the code should result in foo(bar) changing the contents of the angle field.
btw this is not passing by reference, this is passing by pointer. Could you change the title?
Passing by reference (better) would be
void foo(planet& p) {
p.angle += p.angularSpeed;
}
planet bar;
bar.angularSpeed=1;
bar.angle=2;
foo(bar);
You might also consider a constructor for planet that takes as parameters the initial values of angle and angularSpeed, and define a default constructor that sets them both to 0. Otherwise you have a bug farm in the making due to unset values in planet instances.