|
working with allegro datatypes in c++ |
relay01
Member #6,988
March 2006
|
I've noticed that I can't have a bitmap or allegro datatype contained within a class. or at least whenever I try it I get "c++ iso standards forbid" compile errors. Am i missing a way to do this or is it impossible in allegro? _____________________________________ |
23yrold3yrold
Member #1,134
March 2001
|
Quote: I've noticed that I can't have a bitmap or allegro datatype contained within a class. The hell you can't. Post code. -- |
relay01
Member #6,988
March 2006
|
Quote: The hell you can't. Post code. okay
when compiled will give the ISO C++ error... _____________________________________ |
23yrold3yrold
Member #1,134
March 2001
|
Depends what it forbids. Does it forbid using it before it's declared? Do you include allegro.h before that header? I think winalleg.h might cause a funny conflict like that too ... -- |
Elverion
Member #6,239
September 2005
|
DATAFILE* datafile = NULL; You can't do that. The = cannot be used in that fashion for classes. You must use constructors instead. class MyClass { public: DATAFILE *mydata; MyClass(); } MyClass::MyClass() { mydata = NULL; } Also, this is more stylistic than necessary, but you normally do not put the variable names in the declaration of functions (only the variable type is necessary). Leave that for the definitions. EDIT: You also shouldn't use * and & at the same time...It's either one or the other. In this case, you want to use * because you will be passing a pointer. -- |
Kibiz0r
Member #6,203
September 2005
|
Anything that tells you what the class is, goes in the .hpp file, and in the class structure. Anything that does stuff, goes in the .cpp file, and not in the class structure. (unless you want it inlined) Quote: Also, this is more stylistic than necessary, but you normally do not put the variable names in the declaration of functions (only the variable type is necessary). Leave that for the definitions. I disagree with this. Since the header file is generally your reference for how to use the class, wouldn't it be helpful to have descriptive parameter names to make it clear how it should be used? This: certainly tells you less about the function than this: int draw(BITMAP* &buffer, BITMAP* image); The only time I don't name my parameters is when a function is to never be used. For example: class DoNotCopy { private: DoNotCopy(const DoNotCopy&); ... }; Also, to echo Elverion, there are a few instances where you would want to pass a pointer by reference. This, however, is most likely not one of them. --- |
Archon
Member #4,195
January 2004
|
Quote: You can't do that. The = cannot be used in that fashion for classes. You must use constructors instead. MyClass::MyClass() { mydata = NULL; }
It's actually better to use 0 instead of NULL in C++, and it's better to set the initial value in the constructor list, like so: MyClass::MyClass() : mydata(0) { }
|
relay01
Member #6,988
March 2006
|
i appreciate the responses... it appears to be working just as long as I don't set the value to anything... If anybody wants overtime... I'd like some advice on creating a copy constructor... _____________________________________ |
Kibiz0r
Member #6,203
September 2005
|
Copy constructors are in the form of: Example(const Example& other) All classes have a default copy constructor that is genoratored by the compiler based on the member fields. If I have a class like this: class Example { private: int x; }; The compiler tacks on this code, among other things: class Example { private: int x; public: Example(const Example& other) : x(other.x) {} }; So when we do this: Example a; Example b(a); b now has the same value of x as a. So what you want to do is write a constructor that takes a reference-to-const of another instance of the same class as a parameter. Then you want to do whatever is necessary to enforce a predictable behavior from the copy constructor. For most cases, the default constructor should be fine. But sometimes, you have certain concepts of ownership that have to be communicated or special consideration has to be taken because of the contained types. Side-note: Also, if a contained type has no copy constructor -- perhaps it has been disallowed by making it private, you must specify your own because the compiler cannot do it for you. Back to ownership/special consideration...
Looks fine, right? NOOOOOO!!!!! int main() { Bitmap a("my bitmap.bmp"); //ok, make a new Bitmap { //open a new scope Bitmap b(a); //ok, copy the bitmap from a } //PROBLEM: b has gone out of scope and the destructor has been called //Therefore, m_bmp no longer exists! a.DoStuff() //this will then crash } So we need a copy constructor like this: Bitmap::Bitmap(const Bitmap& _other) : m_bmp(create_bitmap(_other.m_bmp->w, _other.m_bmp->h)) { blit(_other.m_bmp, m_bmp, 0, 0, 0, 0, _other.m_bmp->w, _other.m_bmp->h); } Of course, this is a shallow solution. A robust solution would keep a count of references to the bitmap, like boost::shared_ptr, or boost::intrusive_ptr, and delete it when nobody else needs it. But this would be too much code to write to demonstrate a simple concept. --- |
relay01
Member #6,988
March 2006
|
Kibiz0r, thank you for helping me avoid a HUGE bug. _____________________________________ |
Kibiz0r
Member #6,203
September 2005
|
If that saved you trouble, try this:
The default copy constructor and operator= will work as expected because of the semantics of boost::shared_ptr. When all the shared_ptrs that reference the same BmpWrapper are gone, the BITMAP* will be destroyed. This way avoids the memory overhead and CPU time of constantly copying BITMAPs, but is still safe. Note that boost::shared_ptr uses shallow reference counting, which is stored in the boost::shared_ptr itself. So if you make two instances of Bitmap which have the same path, you will have two copies of the same Bitmap. Only copy construction and operator= give you an all-access pass to the wonderful world of managed memory. You can get around that using boost::intrusive_ptr, but then you have to have some central repository of BmpWrappers that are probably organized by a hash of the path string, and you have to define a few functions that Boost needs to use in order to know when to delete them, etc... it's a lot of work to save a handful of KB. --- |
|