Constructor in implementation versus header - c++

The constructor should, to my knowledge, be defined in the implementation file but I've only been able to find examples with the class inside one main file instead of split into a .h and .cpp file
All I need to know is if my following code is separated in an acceptable manner..
Entity.h:
using namespace std;
class cEntity {
private:
/*-----------------------------
----------Init Methods---------
-----------------------------*/
int *X, *Y;
int *Height, *Width;
public:
/*-----------------------------
----------Constructor----------
-----------------------------*/
cEntity (int,int, int, int);
/*-----------------------------
----------Destructor-----------
-----------------------------*/
~cEntity ();
/*-----------------------------
----------Set Methods----------
-----------------------------*/
/*Set X,Y Methods*/
void setX(int x){*X=x;};
void setY(int y){*Y=y;};
void setXY(int x, int y){*X=x; *Y=y;};
/*Set Height, Width Methods*/
void setHeight(int x){*Height=x;};
void setWidth(int x){*Width=x;};
void setDimensions(int x, int y){*Height=x; *Width=y;};
/*-----------------------------
----------Get Methods----------
-----------------------------*/
/*Get X,Y Methods*/
int getX(){return *X;};
int getY(){return *Y;};
/*Get Height, Width Methods*/
int getHeight(){return *Height;};
int getWidth(){return *Width;};
};
and Entity.cpp:
#include "Entity.h"
cEntity::cEntity (int x, int y, int height, int width) {
X,Y,Height,Width = new int;
*X = x;
*Y = y;
*Height = height;
*Width = width;
}
cEntity::~cEntity () {
delete X, Y, Height, Width;
}
I would also like to say thanks to everyone for being so helpful, especially on my first question!

cEntity::cEntity (int x, int y, int height, int width) {
is correct
X,Y,Height,Width = new int;
not so much. That sets Width to a new int, but not the rest. You probably intended:
X = new int(x);
Y = new int(y);
Height = new int(height);
Width = new int(width);
Note that this method of construction will not work for objects without assignment/copy, like references. For some objects, it's also slower than constructing them in place. As such, the preferred way to construct is like so:
cEntity::cEntity (int x, int y, int height, int width) {
:X(new int(x))
,Y(new int(y))
,Height(new int(height))
,Width(new int(width))
{}
This is better, but if any exceptions are thrown, you'll have to somehow deallocate the ones that were allocated. Better is to make each of those members a std::unique_ptr<int>, so they'll deallocate themselves and save you many headaches.

Yes, it's OK.
However, there is a problem with your constructor and destructor.
What your code actually does is allocating one int and your destructor deallocates one int also.
Anyway, there is no need to use pointers here.
Somewhat better implementation (if we don't use smart pointers), could be:
[Entity.h]
private:
/*Private fields*/
int X, Y;
int Height, Width;
[Entity.cpp]
cEntity::cEntity (int x, int y, int height, int width) {
X = x;
Y = y;
Height = height;
Width = width;
}
cEntity::~cEntity () {
}
And one more thing. Try to avoid using namespace std; in your header files. If you do, you force those who include your header to use this using statement and it can provoke namespace clashes.

Your separation is fine. The implementations of those functions is wrong, but you've separated them from the declaration suitably. (They don't allocate or free as many objects as you think they do.)

Yes. For the separation at least, that's generally the best way to do it.
As for the actual implementation you have some issues. I am not really sure what you are trying to do with the constructor or if you have the correct data types for the class member variables but something seems off.

Any method defined in the class directly is implicitly inlined, including the constructor.
I.e.
class MyClass
{
public:
MyClass() {};
};
defines an inline constructor, which may (or may not) improve your code performance,
Whereas
class MyClass
{
public:
MyClass();
};
MyClass::MyClass()
{
};
is not inlined, and therefore won't have those benefits. Both options are correct C++ though.
Just my 2 cents.
P.S And yes, when you decide to store pointers inside a class in this manner, you open a Pandora box.

Related

Segmentation fault when using vectors in the class and constructor

I was doing a list of programming projects, and this project is to make a 15 puzzle (slide puzzle). I was working on the project when I hit a small roadblock.
My code compiles just fine, but when I run it, I get a segmentation fault at line 12: pos[0] = x;
#include <iostream>
#include <vector>
#include <stdlib.h>
#include <time.h>
using namespace std;
class Tile{
private:
vector<int> pos;
int value;
public:
Tile(int x, int y, int value_){
pos[0] = x;
pos[1] = y;
value = value_;
}
~Tile(){}
int getPos(int a){return pos[a];}
void setPos(int a, int b){pos[a] = b;}
};
int main(){
Tile tile1(1, 2, 10);
Tile* t1;
t1 = &tile1;
// returns position "x"
cout << t1->getPos(0);
return 0;
}
I mean, I could just do the whole project without having to use vectors/arrays to handle the position, but I do still want to know, for my own understanding in the future, why this doesn't work.
Based on the debug that I ran, the program is having trouble initializing the value of the pos[] vector.
Another issue: probably related, I tried setting the size of the vector when it was instantiated.
vector<int> pos(2);
But then I get the debug error:
error: expected identifier before numeric constant
Not sure whats going on here. I've tried a bunch of different things but I can't seem to figure out why my vectors don't work inside of classes.
I'm sure there are a hundred ways I could have done this little piece better, and I would love to know how you would have fixed it, but I also need to know what is wrong, specifically in the context of what I have written and tried.
Thanks.
I tried setting the size of the vector when it was instantiated.
vector<int> pos(2);
But then I get the debug error:
error: expected identifier before numeric constant
That's a compilation error, not a debug error.
You can't initialise members like that. However, you can (and should) initialise them using the parent constructor:
Tile(int x, int y, int value_)
: pos(2)
{
pos[0] = x;
pos[1] = y;
value = value_;
}
Currently you're just leaving your vector empty then accessing (and writing to!) elements that don't exist.
You really don't want a vector for this, anyway: that's a lot of dynamic allocation. How about a nice array? Or just two ints.
As mentioned in other answers, your vector is empty and your code is attempting to assign non-existent elements.
The solution is to always use initialisers instead of assignment. Rewrite your constructor as follows:
Tile(int x, int y, int value) :
pos{x, y},
value{value} {}
Note that the constructor body is now empty. All initialisation happens where it should — in the initialiser list.
Apart from that, your class does not need an explicitly defined destructor; the default destructor works just fine.
There are other issues with this class — for instance, what happens when the user does tile.setPos(3, 4)? A rule of thumb of good API design is to make it impossible to misuse the API.
Here’s how I would write your Tile class instead:
struct Tile {
int x;
int y;
int value;
Tile(int x, int y, int value) : x{x}, y{y}, value{value} {}
};
The getter and setter in your case wasn’t really doing any meaningful work. There’s an argument to be made to hide all data members behind accessors to future-proof access control. I’m no longer convinced this is actually useful but just in case, here’s a solution with that, too:
class Tile {
int x_;
int y_;
int value_;
public:
Tile(int x, int y, int value) : x_{x}, y_{y}, value_{value} {}
int x() const { return x; }
int& x() { return x; }
int y() const { return y; }
int& y() { return y; }
int value() const { return value; }
};
This makes x and y readable and writable (via assignment: t.x() = 42;), and value only readable. Other APIs are possible, with different sets of trade-offs. The important thing is to be consistent.
Your constructor doesn't set the size, so when you try to access/modify its contents, you are probably getting the exception.
Tile(int x, int y, int value_) : pos(2) {
pos[0] = x;
pos[1] = y;
value = value_;
}
You can use the initialization list of the constructor to call the vector's constructor, as in the code above.
There are couple of issue in the given code, which I have resolved and added comment in the code.
Issue in setPos and getPos might raise segmentation fault must be handle.
Added checks for the same.
#include <iostream>
#include <vector>
#include <stdlib.h>
#include <time.h>
using namespace std;
class Tile{
private:
vector<int> pos;
int value;
public:
Tile(int x, int y, int value_){
pos.push_back(x); // this is equivalent to pos[0] = x, in this case
pos.push_back(y); // this is equivalent to pos[0] = y, in this case
value = value_;
}
~Tile(){}
int getPos(int a){
if(a >= pos.size()){
return -1; // if a is greater than size then pos[a] will raise the segmentation fault
}
return pos[a];
}
void setPos(int a, int b){
if(a >= pos.size()){
pos.resize(a+1); // to avoid segmentation fault, we are increasing the size if the given index is higher
// resize initialise the value with 0 as default value.
}
pos[a] = b;
}
};
int main(){
Tile tile1(1, 2, 10);
Tile* t1;
t1 = &tile1;
// returns position "x"
cout << t1->getPos(0);
return 0;
}

initialize array in constructor

I want to have a class which has a member array. The size of the array should be given when I initialize the object. I just found a way with pointers to do this. I think it is working correctly, but can you maybe tell me if this is the best way to do it or if there are any things which do not work which I haven't recognized yet?
#include <iostream>
using namespace std;
class Surface {
private:
float dx;
int N;
float* mesh_points;
public:
Surface(float, int);
~Surface();
void set_dx (float);
float get_dx();
};
Surface::Surface(float dx,int N){
this->dx = dx;
this ->N = N;
mesh_points = new float[N];
}
void Surface::set_dx (float dx) {
this->dx = dx;
}
float Surface::get_dx (void) {
return dx;
}
Surface::~Surface(){
delete[] mesh_points;
}
int main () {
Surface s(1.2,10);
s.set_dx (3.3);
cout << "dx: "<< s.get_dx() <<endl;
float mesh_points[3];
return 0;
}
can you maybe tell me if this is the best way to do it or if there are any things which do not work which I haven't recognized yet?
That'd be my take basing on existing best practices:
class Surface {
private:
std::vector<float> mesh_points;
public:
float dx;
Surface(float dx, std::size_t n);
};
Surface::Surface(float dx, std::size_t n)
: dx(dx)
, mesh_points(n)
{
}
In short, the changes made:
Got rid of manual memory management, which implies dtor as well.
Added names for parameters in declarations (really important for usability/IDEs, don't remove them!)
Got rid of superfluous accessors and made dx public.
Used ctor init lists, making the body obsolete.
Got rid of using namespace std; in lieu of explicit std:: prefix.
Changed n type to std::size_t (see comment).
Please note that the current interface doesn't allow any access to mesh_points.
Here's an alternative suggestion that allows you to keep your current implementation but is a lot safer.
class Surface {
private:
float dx;
int N;
float* mesh_points;
public:
Surface(float, int);
~Surface();
void set_dx (float);
float get_dx();
Surface(const Surface&) = delete; // new
Surface& operator=(const Surface&) = delete; // new
};
By deleting the implementation of the copy constructor and copy assignment operator you prevent your Surface objects from being copied (which would likely crash your program anyway). Any attempt to copy Surface objects will now result in a compile time error.
Only a suggestion, my first choice would always be to use std::vector.

Store cursor position in class object (ncurses c++)

I am using QTCreator to compile my c++ code and the <curses.h> library.
Let us say we have the following class definition (.h):
struct coordinateYX
{
int y;
int x;
coordinateYX(long int yPos, long int xPos);
coordinateYX() {}
}
class Rogue
{
private:
long int health;
coordinateYX heroPosition;
public:
long int getHealth();
void setHealth(long int initHealth);
void healthChange(long int vDelta);
coordinateYX getHeroPosition();
void setHeroPosition(coordinateYX hPos);
};
and (.cpp):
coordinateYX::coordinateYX(long int yPos, long int xPos) : y{yPos}, x{xPos} {}
long int Rogue::getHealth() {return health;}
void Rogue::setHealth(long int initHealth) {health = initHealth;}
void Rogue::healthChange(long int vDelta) {health += vDelta;}
coordinateYX Rogue::getHeroPosition() {return heroPosition;}
void Rogue::setHeroPosition(coordinateYX hPos)
{
heroPosition.y = hPos.y;
heroPosition.x = hPos.x;
}
In my main.cpp, I am trying to store the current cursor position into an instantiation of Rogue:
Rogue Hero;
getyx(stdscr, Hero.getHeroPosition().y, Hero.getHeroPosition().x);
But I always get an error:
using temporary as lvalue [-fpermissive]
It also shows this below as part of the error which is in the <curses.h> file
#define getyx(w, y, x) (y = getcury(w), x = getcurx(w))
Although I can simply store these values in another struct initialized in main.cpp, how can I store the x and y positions directly in the class data members?
Thank you.
The quickest solution would be to change getHeroPosition to return a reference instead of value:
coordinateYX& Rogue::getHeroPosition() {return heroPosition;}
The problem is here you are trying to assign to the Rogue position:
getyx(stdscr, Hero.getHeroPosition().y, Hero.getHeroPosition().x);
This is equivalent to:
Hero.getHeroPosition().y = getcury(stdscr);
Hero.getHeroPosition().x = getcurx(stdscr);
But getHeroPosition returns the position by value (it returns a copy, an rvalue). If you assign a value to that temporary copy it will just be lost. The solution is to assign to a reference to the actual Rogue position (an lvalue).
Alternatively, you can use your existing setPosition function:
coordinateYX position;
getyx(stdscr, position.X, position.Y);
Hero.setPosition(position);

How to workaround "redefinition of default parameter" in class constructor

Consider the following example:
class Rectangle{
Rectangle(int x, int y, int width, int height);
Rectangle(int topLeft_x, int topLeft_y, int bottomRight_x, int bottomRight_y);
};
A Rectangle object may be built giving (x,y) coordinates plus width and height or giving top left points pair and bottom right points pair.
While this is correct from an object oriented point of view, this is not from a compiler point of view, returning the error "member function already defined or declared"
While I normally fix this condition easily in case of member function, simply changing the name according to what it does, this is not possible for constructors.
What is the simpler and correct way to workaround this issue keeping both the way to construct the object?
Another possible solution (other than the pair suggested by #VladfromMoscow) is a static method to perform construction. This lets you give them distinct names, since their argument lists are so similar. Thisi is called the Named Constructor Idiom
class Rectangle
{
public:
static Rectangle createRectangle(int x, int y, int width, int height)
{
return Rectangle(x,y,width,height);
}
static Rectangle createRectangleCorners(int x1, int y1, int x2, int y2)
{
return Rectangle(x1,y1,x2-x1, y2-y1);
}
private:
// Doesn't have to be private, but this forces users to use the above
// constructors
Rectangle(int x, int y, int width, int height);
}
You wrote already yourself
top left points pair and bottom right points pair
So what you need is to define class Point and use this type in the constructor declaration.
Otherwise the constructors are declared like
class Rectangle{
Rectangle(int, int, int, int);
Rectangle(int, int, int, int);
};
As you see these declarations do not make sense even if you will write multiline comments.:)
Another approach is to declare the first constructor like
class Rectangle{
Rectangle(int x, int y, unsigned int width, unsigned int height);
Rectangle(int topLeft_x, int topLeft_y, int bottomRight_x, int bottomRight_y);
};
However this approach is unsafe because each integer literal specified as the third or fourth argument must be casted.
Instead of the class Point you could use standard class std::pair. For example
#include <utility>
//...
class Rectangle{
Rectangle(int x, int y, int width, int height);
Rectangle( const std::pair<int, int> &topLeft, const std::pair<int, int> &bottomRight);
};
Another way on how to solve this problem is by using Tag dispatching:
Instead of using methods with different names, give them a new parameter, e.g.,
struct useCorners {};
struct useDimension {};
class Rectangle
{
Rectangle(useCorners, int topLeft, int topRight, int bottomLeft, int bottomRight)
{ ...
}
Rectangle(useDimension, int topLeft, int topRight, int width, int height)
{ ...
}
};

Creating a 2D array on construction with a variable length

How can a setup a class that I can have a private 2D array that's size is determined by the variables passed in via the constructor?
I've tried this:
class World {
private:
const int WIDTH;
const int HEIGHT;
bool map[][];
public:
World(const int MAX_X, const int MAX_Y) : WIDTH(MAX_X), HEIGHT(MAX_Y) {
map = new bool[WIDTH][HEIGHT];
}
};
But I get a bunch of errors about how declaration of ‘map’ as multidimensional array must have bounds for all dimensions except the first and array size in operator new must be constant even though it is.
I've also tried it this way but it didn't work either:
class World {
private:
const int WIDTH;
const int HEIGHT;
bool map[WIDTH][HEIGHT];
public:
World(const int MAX_X, const int MAX_Y) : WIDTH(MAX_X), HEIGHT(MAX_Y) {
//map = new bool[WIDTH][HEIGHT];
}
};
I get a invalid use of non-static data member ‘World::WIDTH’ on the const int WIDTH line and a quite useless error: from this location on the map declaration line.
What am I doing wrong?
Edit:
I'd prefer to avoid using vectors since I haven't "learned" them yet in this class. (by learned I mean I know how to use them but the professor hasn't discussed them and doesn't like us using outside knowledge)
You could use a vector.
class World
{
typedef std::vector<bool> Tiles;
typedef std::vector<Tiles> WorldMap;
World(unsigned int width, unsigned int height)
{
for (unsigned int i = 0; i < width; i++)
{
m_map.push_back(Tiles(height));
}
}
private:
WorldMap m_map;
};
Or you could use templates, if you know the world size at compile time.
template <unsigned int Width, unsigned int Height>
class World
{
private:
bool m_map[Width][Height];
};
Or you could use raw pointers, since a 2d array is really just an array of pointers to arrays.
class World
{
// Make sure you free this memory.
World(unsigned int width, unsigned int height)
{
m_map = new bool*[width];
for(unsigned int i = 0; i < height; ++i)
{
m_map[i] = new bool[width];
}
}
private:
bool** m_map;
};
I suggest using one of the first two options.
Arrays must have their sizes determined at compile-time, not run time.
You should choose a different container if you want run-time sizing. Possibly:
- std::vector<bool> // and then simulate a 2d array using indexing
- std::vector<std::vector<bool>> // if you insist on using [][] syntax