5

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!

Nick Savage
  • 856
  • 1
  • 7
  • 18
  • I suggest looking into boost.shared_ptr / boost.scoped_ptr. They handle deletion on destruction and your risk of memory leaks is lower. Also, make the destructor `virtual` unless you have a reason for not doing so. – moshbear Nov 11 '11 at 22:20
  • 2
    I suggest looking into non-pointer types. – avakar Nov 11 '11 at 22:21
  • 4
    `delete X, Y, Height, Width;` this does not do what you think it does. – K-ballo Nov 11 '11 at 22:22
  • also only Width will be allocated... – joy Nov 11 '11 at 22:24
  • Alright I assume you mean I'd need a separate 'delete' per variable? And I'll read up on the boost library and virtual keyword. – Nick Savage Nov 11 '11 at 22:25
  • @NickTgodSavage, don't use `delete` at all. Nor `new`. There is no reason to use pointers. – avakar Nov 11 '11 at 22:29
  • @moshbear: why make the destructor virtual, I see no implication that this will be inherited from. – Mooing Duck Nov 11 '11 at 22:30
  • Yes, Nick. *If* you're going to use pointers here, you need a `new` and a `delete` for each variable. But you don't really need pointers for these at all. Just use plain `int` variables. – Rob Kennedy Nov 11 '11 at 22:30
  • Ah the example I was basing this of off showed using pointers was an effective way of handling things although it seems the example could be a little outdated. The cEntity class is the base class for the derived cOrganism which is the base class for cNPC, cPlayer, and cEnemy classes. Perhaps this is too advanced for my knowledge at the moment but this is the concept I obtained from reading on basic inheritance. – Nick Savage Nov 11 '11 at 22:36

5 Answers5

5
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.

Eiko
  • 25,601
  • 15
  • 56
  • 71
Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
  • Interesting, thanks for showing me alternative construction methods.. I'm very new to all of this but I'm attempting to learn :P – Nick Savage Nov 11 '11 at 22:29
  • 2
    Or don't make them pointers at all. Then their allocation is within the object itself and they will be freed when the cEntity object is destroyed. – Michael Price Nov 11 '11 at 22:51
  • @MichaelPrice: I assumed they were pointers for a reason, but you raise a good point. – Mooing Duck Nov 11 '11 at 22:54
  • I've removed all pointers from this example. However doesn't this imply that I will be unable to create new instances of my class in real time while the program is running? – Nick Savage Nov 11 '11 at 22:55
  • @NickTgodSavage No. You can still say `new cEntity();` or whatever derived class you want on the heap. Technically, even objects that live on the stack are created "in real time" (with the possible exception of non-reference, `const` objects [see constexpr in C++11] or with globals [allocated at program startup]). – Michael Price Nov 11 '11 at 23:01
  • @NickTgodSavage: Not at all! The variables are _inside_ of the object itself. Wherever you have a `cEntity`, it holds (in your case) 4 `int`s inside of itself. – Mooing Duck Nov 11 '11 at 23:01
  • Excellent, thanks for the explanation! I was aware that each instance of my class had its own variables but I was unaware that I'd be able to create say... doSummonCreate(); and initiate a new instance of the derived cEnemy class without having memory leaks – Nick Savage Nov 11 '11 at 23:05
  • @NickTgodSavage: Actually, having pointers _increases_ the likelyhood of memory leaks. Keep in mind if things inherit from `cEntity`, you'll want to do what moshbear recommended and make the destructor `virtual` – Mooing Duck Nov 11 '11 at 23:12
  • @MooingDuck Alright, I'll definitely read up on the virtual keyword – Nick Savage Nov 11 '11 at 23:18
3

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.

Marek Kurdej
  • 1,459
  • 1
  • 17
  • 36
  • So would it be best to just make use of 'std::' or is there another way of excluding the namespace? – Nick Savage Nov 11 '11 at 22:27
  • Nick, please see this question: [Why shouldn't I put "using namespace std" in a header?](http://stackoverflow.com/questions/3186226/) – Rob Kennedy Nov 11 '11 at 22:34
  • You don't need accessing std namespace in your code here. And yes, when you need, you'll use `std::`. – Marek Kurdej Nov 11 '11 at 22:36
  • The std namespace IS needed further on in the code this is simply a section that I wanted information on. Further down I utilize strings and vectors as well. – Nick Savage Nov 11 '11 at 22:37
1

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.)

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
0

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.

Pepe
  • 6,360
  • 5
  • 27
  • 29
-1

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.

AlexK
  • 1,279
  • 8
  • 19
  • Would it be more wise to just skip the implementation file for this scenario and use an inline constructor? – Nick Savage Nov 11 '11 at 22:54
  • Depends. Interfaces are meant to be short, clean and easy to understand. If there's a lot of code in your constructor, it will pollute your interface file. Your 4-line constructor is probably OK inside .h though. – AlexK Nov 11 '11 at 23:12
  • "Any method defined in the class directly is implicitly inlined" really doesn't make sense. The compiler will decide if something is going to be inlined based on some implementation defined behavior. – Michael J. Gray Jun 17 '17 at 02:42