Some C++ Class questions...

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Acki
Posts: 3496
Joined: Tue Jun 29, 2004 12:04 am
Location: Nobody's Place (Venlo NL)
Contact:

Post by Acki »

hybrid wrote:Because a struct with a constructor is a class without private or protected members?
so you can derive new structs from other structs with inheritances and such !?!?! :shock:
also just because of the constructor can't be the reason, because a struct doesn't need a constructor (but can have one), it was just an example I wrote... ;)
while(!asleep) sheep++;
IrrExtensions:Image
http://abusoft.g0dsoft.com
try Stendhal a MORPG written in Java
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

The _only_ difference between a struct and a class in C++ is the default access level. For structs it is public, and for classes it is private. Both can have constructors, destructors, assignment operators and member functions. Both can be used to define a plain-old-data types.
Also, I'm pretty sure that when you declare a pointer, int, float, etc. in a class it is automatically initialized to zero. It is only left uninitialized (garbage) if you declare it in a function.
This is only true in certain contexts. I don't have the C++ standard available to me at the moment, so I'm going from memory here, but I believe that the rule is that data with static storage duration is default initialized to 0. That means global variables [namespace scope variables], static class members, and static local variables are all zero initialized at static initialization time, unless you provide some other explicit initializer.

That means that class/struct member variables will be garbage unless you explicitly initialize them.

Travis
christianclavet
Posts: 1638
Joined: Mon Apr 30, 2007 3:24 am
Location: Montreal, CANADA
Contact:

Post by christianclavet »

Wow! Thanks guys!

You showed me that I still have a lot to learn about C++ and OOP programming. I had only a base in PASCAL from a long time ago (1986), tried a little in C in 1998. Got DEVCPP last march and downloaded IRRlicht.

I'll check more about what you talked in this thread and google about them. What is a singleton? I used struc in Pascal, but since I looked how the classes worked, I'd prefer to stick with classes, unless there is a clear disadvantage in using them. From what I learned so far, they are fairly similar in functionnality.
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

vitek wrote:The _only_ difference between a struct and a class in C++ is the default access level.
Which, just to clarify, includes the default inheritance type.

Note that you can perfectly validly derive a struct from a class, or vice versa.

mqrk wrote:Also, I'm pretty sure that when you declare a pointer, int, float, etc. in a class it is automatically initialized to zero. It is only left uninitialized (garbage) if you declare it in a function.
Let's puzzle it out together.

Code: Select all

#include <stdio.h>
class CClassy
{
public:
    void * foo;
    static void * bar;
};

// Note: no explicit value is assigned, but because it's static
// it gets zero initialised.
void * CClassy::bar;

struct SDerivedDefault : /* public is implicit here */ CClassy { };

class CDerivedPublic : public CClassy { };

class CDerivedDefault : /* 'private' is implicit here */ CClassy { };

void main()
{
    // Note that nothing is assigned, so you get whatever garbage is in the stack.
    void * garbage;
    // Nice compilers will warn you about using an uninitialised variable
    printf("garbage %p\n", garbage);

    // Nothing is assigned, but static memory comes off the heap, and is zero initialised.
    static void * zero;
    printf("zero %p\n", zero);

    // Note the lack of () brackets - no initialisation is performed.
    CClassy * garbageHeap = new CClassy;
    printf("garbageHeapFoo->foo %p\n", garbageHeap->foo);
    printf("garbageHeapFoo->bar %p\n", garbageHeap->bar);

    // Note the () brackets - and as if by magic, it's zero initialised.
    CClassy * zeroHeap = new CClassy();
    printf("zeroHeapFoo->foo %p\n", zeroHeap->foo);
    printf("zeroHeapFoo->bar %p\n", zeroHeap->bar);

    // You just get whatever happens to be in the stack's memory.
    CClassy garbageStack;
    // Nice compilers will warn you about using an uninitialised variable
    printf("garbageStackFoo.foo %p\n", garbageStack.foo);
    printf("garbageStackFoo.bar %p\n", garbageStack.bar);

    // This expliticly zeros the first member, and any others will be 
    // implicitly set to 0 as well.  This implicit behaviour is guaranteed
    // by the spec.
    CClassy zeroStack = {0};
    printf("zeroStackFoo.foo %p\n", zeroStack.foo);
    printf("zeroStackFoo.bar %p\n", zeroStack.bar);

    // We can access the members of SDerivedDefault as it preserves the public access of CClassy
    SDerivedDefault derivedStruct;
    derivedStruct.foo = derivedStruct.bar;

    // We can access the members of CDerivedPublic as it preserves the public access of CClassy
    CDerivedPublic publicDerivedClass;
    publicDerivedClass.foo = publicDerivedClass.bar;

    // However, we can't access the members of CDerivedDefault because when it inherits the 
    // public members of CClassy, it implicitly makes them 'private'
    CDerivedDefault defaultDerivedClass;
    // defaultDerivedClass.foo = defaultDerivedClass.bar; // This won't compile
}
...

garbage 781C37E4
zero 00000000
garbageHeapFoo->foo 00310380
garbageHeapFoo->bar 00000000
zeroHeapFoo->foo 00000000
zeroHeapFoo->bar 00000000
garbageStackFoo.foo 781C37E4
garbageStackFoo.bar 00000000
zeroStackFoo.foo 00000000
zeroStackFoo.bar 00000000
Last edited by rogerborg on Sat Dec 15, 2007 7:09 pm, edited 1 time in total.
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

rogerborg wrote:
vitek wrote:The _only_ difference between a struct and a class in C++ is the default access level.
*cough* And default inheritance. *cough* ;)
Yes. I didn't explicitly say so, but the default access level applies to inheritance also.

Very nice example, BTW.
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

Sure, I'm just spelling it out. Well, I am now. ;)

It's probably wrong to love these nuances of C/C++, but it feels so right. Cognitive dissonance and all that.
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
Vsk
Posts: 343
Joined: Thu Sep 27, 2007 4:43 pm

Post by Vsk »

Wait a moment, if use struct (stack) you can NOT use polymorphism right?
So why should you hava a struct derived from a class?. Just for Variables??

The proper way in OOP is to use pointers of classes for Objects and structs or class in stack (not pointers) for Datatypes.

An Object is Class Instance it has state and behavior and it has IDENTITY. (Pointers implement this perfectly, whey you work in the stack (without pointers DON'T) This last one is I think the problem that you intialy had, stack object hasn't identity, his identity loosed at the end of the actual scope. (pointer don't, -heap).

A datatype it just a "data storage" convenince becasue it make easy modifigin code if you add new parameter to for example a function.

For "gameinfo" actually i'm using a singleton that handles graphic aspect and abstracts me from irrlicht (kinda hard abstrac 3d engines :~).

There are other benefits for pointers like Identity, polymorphism, faster collections from objects. etc.
The only discution about them is that this is not java, so we have not garbage colector :-(. So some people have problem with memory.
So you can work with struct or class in stack and try to simplify yoursefl and loose or the pointer advantages. Or you use clases (with pointers) and take a little care with (the only problem) deletes.
Besides you can use some library like Boost for pointer counter.

It hope it helps.
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

Vsk wrote:Wait a moment, if use struct (stack)
Whoa, back up. In C#, classes and structs are distinct, and structs are stack objects. This is not the case in C++. In C++, classes or structs can be allocated either on the heap or the stack.
Vsk wrote:you can NOT use polymorphism right?
Wrong. Class, struct, heap, stack has no bearing at all on polymorphism in C++.

Vsk wrote:So why should you hava a struct derived from a class?
No particular reason, it's just by way of illustrating that you can do it in C++, because (once again for luck) the only difference between a class and a struct is the default access and inheritance.

A common and useful convention is to use structs where you only need to store a collection of data, but that is purely a convention. The compiler doesn't care.

[Yoda]No! No different! Only different in your mind. You must unlearn what you have learned.[/Yoda]
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
Vsk
Posts: 343
Joined: Thu Sep 27, 2007 4:43 pm

Post by Vsk »

You are saying that I can use dinaymic dispatch with the stack?

If I use

Base A{

funcion();
};
Son B:public A;{
funcion(){
overrided.
};
}


A objetoGen = B(); (withour new, in the stack).

objetGen.function() will dispatch A method or b method?
Saturn
Posts: 418
Joined: Mon Sep 25, 2006 5:58 pm

Post by Saturn »

A::function is called. rogerborg is mistaken in the point that there is no difference between stack and heap storage regarding polymorphism. Everything else he wrote is correct though.

For stack storage the size of an object has to be known in advance, so that the compiler can make room for it on the stack upon entering the block/function. Since the derived type B could have a larger size by using new members the compiler can't decide statically whether it is safe to call the virtual function of B because it could use these new members. The compiler could maybe for your example, but one can think up programs where it just can't. And since it is better to be consistent, no B functionality is used for stack allocated objects.

Object of type B is reduced to the functionality and size of A in this case. Virtual function overrides in B are ignored. This is called slicing.
Halifax
Posts: 1424
Joined: Sun Apr 29, 2007 10:40 pm
Location: $9D95

Post by Halifax »

[quote="fireside"]Pointers can get you in trouble so be careful with them. The less the better as far as I'm concerned.quote]

That's not really true, especially since pointers are the pinnacle of optimized programming. ;)

Would you rather waste time passing a 128 byte struct over the stack for ever call to a function, or a 4 to 8 byte pointer(depending on your processor).
TheQuestion = 2B || !2B
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

rogerborg is actually correct. Stack or heap don't matter.
That example does something different:

Code: Select all

A objetoGen = B(); (withour new, in the stack). 
It will create B on the stack but copy it afterwards to A. Which is bad behavior anyway. And certainly A functions are called thereafter because it *is* an A object.

But you can create B on the stack and it's virtual functions are called. I made a small example for all the cases (so Rogerborg doesn't have to do all the work here ;-) ):

Code: Select all

#include <cstdio>

class A
{
public:
	void foo()			{ printf("A::foo()\n"); }
	virtual void bar()	{ printf("A::bar()\n"); }
};

class B:public A
{
public:
	void foo() 			{ printf("B::foo()\n"); }
	void bar()			{ printf("B::bar()\n"); }
};
 
int main(int argc, char *argv[])
{
	A copy_that = B();
	B onStack;
	B * onHeap = new B();
	
	copy_that.foo();
	copy_that.bar();
	
	A * ptrToIt;
	ptrToIt = &onStack;
	ptrToIt->foo();
	ptrToIt->bar();
	
	ptrToIt = onHeap;
	ptrToIt->foo();
	ptrToIt->bar();
	
	delete onHeap;
}
Result is:
A::foo()
A::bar()
A::foo()
B::bar()
A::foo()
B::bar()

So it does not depend if B is create on stack or heap but only if the function is virtual and of which type the object was on creation.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
fireside
Posts: 158
Joined: Thu Dec 01, 2005 10:55 pm

Post by fireside »

That's not really true, especially since pointers are the pinnacle of optimized programming.
I agree they are necessary. I just try to keep it to a minimum. A lot of the time you can pass by reference. I think people get carried away with them. If I create an actual object, then the program takes care of the memory. If I put the object in an array, it acts like a pointer sort of, but I don't have to worry about it. I'm not quite the VSK or rogerBorg type. Nothing wrong with that, I just don't have the mind for it, or maybe the interest. The dynamic stuff can actually slow a program down, and for me it's a crash waiting to happen.
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

I suppose whether you consider that to be screwing polymorphism depends on your expectations. If you declare an A (rather than pointer-to-A) and expect to ever get anything other than an A, with A's methods, then you'll be disappointed - even emotionally bruised. You may need counseling, or at least a big hug.
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
fireside
Posts: 158
Joined: Thu Dec 01, 2005 10:55 pm

Post by fireside »

It works for me and I'm not too emotionally scarred. I just get less crashes that way.
Post Reply