Advertisement

C++ Classes pointing to eachother? Seems it should work somehow...

Started by November 22, 2000 04:12 PM
11 comments, last by BeanDog 24 years, 2 months ago
I have 2 C++ classes: class d3dObject { public: d3dObject* subobjs[500]; //use to build hierarchy d3dApp* d3d; }; class d3dApp { public: d3dObject* objs[500]; }; Obviously I cut out all the excess junk. But here''s the basic idea. Each d3dObject has to have access to the d3dApp that contains it in the d3dApp''s d3dObject* array. But the d3dApp object therefore has to have a pointer to d3dObjects. How to I pull this off without compiler error? ~BenDilts( void );
Cyclic dependency. You could delcare the class without inculding the header in one of the classes. Like such.

//delcare the class
class d3dApp;

class d3dObject
{
public:
d3dObject* subobjs[500]; //use to build hierarchy
d3dApp* d3d;
};

just make sure you include the d3dApp header in the .cpp file of d3dObject.

Good Luck.

-ddn
Advertisement
Thanks a lot! I didn''t realize you could have 3 levels of declaration for a class.



~BenDilts( void );
Yeah its something called the one-definition rule. As long as you don''t define the class/structure twice its cool.

This is used quite a lot when programming using patterns:

The bridge pattern:

class Window {    public:        Window();       ~Window();    private:        class WindowImpl;        WindowImpl    *p;}; 


By doing this you can then define WindowImpl in another header or source file. This has two benefits: 1) it reduces compile time dependencies and 2) allows you to abstract the inner workings of the Window class away from the client. This is really cool if you want to ship libraries with header files etc. The best benefit from this technique is that WindowImpl could be defined to create a window in Linux or Windows and the interface to the client won''t change.

// in winimpl.hclass WindowImpl{    public:        // define interface for working with windows        virtual ~WindowImpl();        virtual CreateWindow(long StyleBits) = 0;        virtual DestroyWindow() = 0;};// in another file: win32_windowimpl.hclass Win32_WindowImpl : public WindowImpl{    public:        // implement WindowImpl interface};// in another file: xwindows_windowimpl.hclass XWin_WindowImpl : public WindowImpl{    public:        // implement WindowImpl interface}; 


Now, in Window''s constructor you can do:

Window::Window(){    #ifdef _WIN32        p = new Win32_WindowImpl;    #else        p = new XWin_WindowImpl;    #endif} 


Through polymorphism and abstraction of interfaces we can create a Windows and Linux build of our program with a simple declaration of a compiler directive.

Another technique is to use an AbstractFactory class to create the correct Window implementation. This is done at run-time but since Win32 and XWindows don''t tend to be running at the same time we can use compile time directives.

Cool? Hopefully I didn''t bugger this up

Dire Wolf
direwolf@digitalfiends.com
[email=direwolf@digitalfiends.com]Dire Wolf[/email]
www.digitalfiends.com
Hi, I''m just an outside observier. But I feel I should pipe in and say ''damn thats cool''.


That''s it.
--------------------------I guess this is where most people put a famous quote..."Everything is funnier with monkey''s" - Unknown
Thanks.

I picked up that technique way back in College, rediscovered it after reading Bjarne Stroustrups, "The C++ Programming Language 3rd Edition", and then again (and re-affirmed as a real pattern) in GoF''s, "Design Patterns: Elements of Reusable Object-Oriented Software".

Dire Wolf
direwolf@digitalfiends.com
[email=direwolf@digitalfiends.com]Dire Wolf[/email]
www.digitalfiends.com
Advertisement
I'm reading that book too, the first 20 pages or so were simply mind blowing. I was amazed at how much OOP code I knew, and yet knew nothing of OOD.

It quickly became a yawn after yet, seeings how it reads like the text book that it is. (I still intend to force my way through it, I just wish it wasn't so dry - I suddenly really appreiate all of LaMonthe's snide comments)

So I feel your painpain BeanDog, my "OOP" code was always full of back pointers and I always felt that there should be a better way.

A couple of golden rules I've decided upon:
Write the main app section of code that will call/use the object first.
Don't make your class handle any more work than it must.


Sooo, you should have a 3DEngine class that sets up D3D & have some sort of Create3DObject method, that returns a 3DObject pointer (antoher class). If it needs a private member of the 3DEngine class for construction, pass it as a parameter to the 3DObject constructor. If you design it right, you shouldn't need a back pointer actually stored in the class. The 3DObject will create its own VBBuffer, probably as a public member, so that the 3DEngine can be handed a container iterator to rip through & render all the 3DObject's VBBuffers.
If you really do need a back pointer in the 3DObject class, at least make it static.

Edited by - Magmai Kai Holmlor on November 25, 2000 2:18:27 AM
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
MagMai, if you want a "real world book" for using design patterns check this book out:

Pattern Hatching: Design Patterns Applied
John Vlissides, Addison-Wesley ISBN: 0-201-43293-5

The book is an incredible read and shows various uses of the Composite, AbstractFactory, Singleton, Observer, Visitor etc. Its a very small book and an easy read. The Design Pattern textbook tends to make good reading material when you can''t sleep

Dire Wolf
direwolf@digitalfiends.com

BTW BeanDog:

Why do you need to statically declare the size of the d3dobject array (in the d3dObject class)? Also why do you need to point back to the d3dApp class?

[email=direwolf@digitalfiends.com]Dire Wolf[/email]
www.digitalfiends.com
Why do I declare the size statically?

I''m lazy. I''ll fix it.

Why do I need to point back? Because the App has a Render() function which calls each of the objects'' Render() functions, which need to refer back to several of the App''s member variables (ambient lighting for my in-house lighting, etc.). Actually, each of the objects, as it lights its vertices and moves them into world space, concatenates its vertices into arrays in the App object - 1 array for each texture. Thus, only one DrawPrimitive call per texture for an entire frame is needed. This speeded up my engine dramatically.



~BenDilts( void );
That''s exactly what you don''t want to do

Have a the render function in the d3dapp class, and either keep a container of of the 3dobjects it creates in the class, or have some way to attach a container of 3dobjects to it. You don''t want to have to call a function for every object in the game. You want an inlined GetFirst, GetNext, and a simple dereference to get at the VB.
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara

This topic is closed to new replies.

Advertisement