I put all objects in "Object[x]" by using the object superclass. How can I tell "Object[x]" to call the cChild classes after it has been constructor-ed as a cChild object?
Here is my code:
1 | #include <allegro.h> |
2 | |
3 | // Superclass of all objects |
4 | class cObject { |
5 | public: |
6 | cObject() { |
7 | allegro_message("Object created"); |
8 | } |
9 | |
10 | ~cObject() { |
11 | allegro_message("Object destroyed"); |
12 | } |
13 | |
14 | void something() { |
15 | allegro_message("Object called"); |
16 | } |
17 | |
18 | }; |
19 | |
20 | // A custom defined object |
21 | class cChild : public cObject { |
22 | public: |
23 | cChild() { |
24 | allegro_message("Child Created"); |
25 | } |
26 | |
27 | ~cChild() { |
28 | allegro_message("Child destroyed"); |
29 | } |
30 | |
31 | void something() { |
32 | allegro_message("Child called"); |
33 | } |
34 | }; |
35 | |
36 | // Object Array |
37 | cObject *Object[2]; |
38 | |
39 | // main |
40 | int main() { |
41 | allegro_init(); |
42 | |
43 | allegro_message("MAIN(): New Objects - cChild"); |
44 | Object[1] = new cChild(); |
45 | Object[2] = new cChild(); |
46 | |
47 | allegro_message("MAIN(): Object->something();"); |
48 | Object[1]->something(); |
49 | Object[2]->something(); |
50 | |
51 | allegro_message("MAIN(): delete Object[]"); |
52 | delete Object[0]; |
53 | delete Object[1]; |
54 | delete Object[2]; |
55 | |
56 | allegro_exit(); |
57 | } |
58 | END_OF_MAIN(); |
--- EDIT ---
The output is:
"MAIN(): New Objects - cChild"
"Object created"
"Child created"
"Object created"
"Child created"
"MAIN(): Object->something();"
"Object called"
"Object called"
"MAIN(): delete Object[]"
"Object destroyed"
"Object destroyed"
there are some casting operators, like
dynamic_cast and static_cast,
I think that the array of pointers to cObject, cannot use anything from cChild, unless you define virtual methods or use a cast.
Don't you have to make the methods virtual? I think that'll fix it.
How would you make a constructor / destructor 'virtual'?
----- EDIT -----
making the superclass (cObject) void something() virtual, worked. I only need to put this on superclasses right?
I belive so. And maybe make the destructor virtual too... "I think"
class BaseClass { public: virtual ~BaseClass(); // not sure if thats valid though, I assume it is. ... }
OK, I cannot make constructors virtual but I can make destructors virtual.
Also when I make destructors virtual, then both destructors are called.
So here is the code updated:
1 | #include <allegro.h> |
2 | |
3 | // Superclass of all objects |
4 | class cObject { |
5 | public: |
6 | cObject() { |
7 | allegro_message("Object created"); |
8 | } |
9 | |
10 | virtual ~cObject() { |
11 | allegro_message("Object destroyed"); |
12 | } |
13 | |
14 | virtual void something() { |
15 | allegro_message("Object called"); |
16 | } |
17 | |
18 | }; |
19 | |
20 | // A custom defined object |
21 | class cChild : public cObject { |
22 | public: |
23 | cChild() { |
24 | allegro_message("Child Created"); |
25 | } |
26 | |
27 | ~cChild() { |
28 | allegro_message("Child destroyed"); |
29 | } |
30 | |
31 | void something() { |
32 | allegro_message("Child called"); |
33 | } |
34 | }; |
35 | |
36 | cObject *Object[0]; |
37 | |
38 | // main |
39 | int main() { |
40 | allegro_init(); |
41 | |
42 | Object[0] = NULL; |
43 | |
44 | allegro_message("MAIN(): New Objects - cChild"); |
45 | Object[0] = new cChild(); |
46 | |
47 | allegro_message("MAIN(): Object->something();"); |
48 | Object[0]->something(); |
49 | |
50 | allegro_message("MAIN(): delete Object[]"); |
51 | |
52 | delete Object[0]; |
53 | |
54 | allegro_exit(); |
55 | } |
56 | END_OF_MAIN(); |
Output:
"MAIN(): New Objects - cChild"
"Object created"
"Child Created"
"MAIN(): Object->something();"
"Child called"
"MAIN(): delete Object[]"
"Child destroyed"
"Object destroyed"
Notes:
I put virtual on the superclass
- virtual void something();
- virtual ~cObject();
With constructors, cObject is called first then cChild's.
With destructors, cChild is called first then cObject's.
Code update compared with previous, I am only using 1 object now to make it easier...
1) you can't make constructors virtual since it's completely pointless - how should virtual constructor be different from non-virtual one?
2) base class constructor is always called before derivate class constructor and base class destructor is always called after derivate class destructor, no matter they are virtual or not
maybe I should just leave the constructors and destructors empty for superclasses then
In every destructor you should free memory allocated by that constructor. Don't make your child delete memory which was allocated by the base constructor, because you are likely forget to copy that code in another child destructor, generating a memory leak.
Yeah, use ctors/dtors for what they are useful for. In polymorphism, use them to initialize elements in that class alone.
Destructors should be virtual if you ever delete an object through a pointer-to-base type. Usually I make destructors always virtual if I'm using inheritance, just to be safe.
OK, I cannot make constructors virtual but I can make destructors virtual.
Quite right.
With constructors, cObject is called first then cChild's.
With destructors, cChild is called first then cObject's.
Also quite right.
maybe I should just leave the constructors and destructors empty for superclasses then
At least initialize all member variables. Wise practice.
So the problem is all solved then?
ReyBrujo is right. Some example should help understanding it.
class cBase { public: char *bunch_of_bytes; cBase() { bunch_of_bytes = new char[100]; } virtual ~cBase() { delete bunch_of_bytes; } }; class cDerived : public cBase { public: char *another_bunch_of_bytes; cDerived() { another_bunch_of_bytes = new char[50]; } virtual ~cDerived() { delete another_bunch_of_bytes; } };
Base class allocates some memory. When derived class constructor is called, it can assume that base class is fully initialized, since its constructor was called and allocated the memory. Now, derived class wants to allocate some more memory. Derived class destructor has only to free memory allocated in derived class constructor, since base class destructor gets called automatically after it and will free base class allocated memory.
[edit: forgot ': public cBase' in code]
Just be shure you dont do anything like this with your destructors.
1 | CBaseClass |
2 | { |
3 | public: |
4 | CBaseClass(); |
5 | virtual ~CBaseClass(); |
6 | |
7 | protected: |
8 | CSurface *m_Surface; |
9 | } |
10 | |
11 | CBaseClass::CBaseClass() : m_Surface(NULL) |
12 | { |
13 | m_Surface = new CSurface; |
14 | } |
15 | |
16 | CBaseClass::~CBaseClass() |
17 | { |
18 | delete m_Surface; |
19 | } |
20 | |
21 | CDervivedClass::CDervivedClass() : CBaseClass() |
22 | { |
23 | |
24 | } |
25 | //Up to now everything should be normal, but this constructor is wrong. |
26 | CDervivedClass::~CDervivedClass() |
27 | { |
28 | delete m_Surface; |
29 | } |
30 | |
31 | //General Rule is dont free anything from the memory that you did not create. |
You could also implement the base class functions as pure virtual.
virtual void Jump(int Height) = 0;
Edit : Beaten by a few hours.. ah well.
One more rule: If you have any virtual methods in a class, the destructor must be virtual, too. Otherwise, the child's destructor overwrites the parent's one, and the wrong destructors get called. At least, that's what my C++ book says.
One more rule: If you have any virtual methods in a class, the destructor must be virtual, too. Otherwise, the child's destructor overwrites the parent's one, and the wrong destructors get called. At least, that's what my C++ book says.
That's right, but for the wrong reason. The destructor should be virtual if you can expect the class to be derived from at some point, and virtual methods are generally a good indicator of that.
You are not required to make a destructor virtual in any circumstance, but it is good style to make the destructor virtual if any of its methods are virtual. But as long as you always know the exact type of an object when you delete it, then you don't need virtual destructors. But, if you are using virtual methods, then you probably don't know the type at delete time, so if you have virtual methods, 99% of the time you'll want virtual dtors as well.