PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Unvollständige Klassendefinitionen


Gnafoo
2005-05-05, 14:36:24
Hi

Ich arbeite gerade an einem Programm, welches zum einen in C++ geschrieben ist und zum anderen Ruby als Sprache nutzt. Die Schnittstelle zwischen beiden Sprachen lasse ich mir von SWIG (http://www.swig.org) generieren.

Dabei wird eine C++ Datei generiert, welche auf den eigentlichen C++-Code meines Programmes in Form einer statischen Library zugreift. Der generierte Code wird zum Erstellen einer dynamischen Library benutzt, welche dann von Ruby geladen wird um die Klassen etc. bereitzustellen.

Die dabei generierte C++ Datei inkludiert (sagt man das so? :D) nun ganz am Anfang "ruby.h", um die Klassen etc. an Ruby weitergeben zu können. "ruby.h" wiederum definiert mehrere Macros, welche später zu Problemen führen, sobald ich die Header-Files zu Ogre (http://www.ogre3d.org), welches ich im eigentlichen C++-Code nutze inkludiere. Die Makros kann ich aber so einfach nicht umgehen.

Die Klassendefinition (Application.h), um die es dabei geht sieht wie folgt aus:
#include <Ogre.h>

class Application : public Ogre::Singleton<Application>
{
public:
Application(void);
virtual ~Application(void);

static Application& getSingleton(void);
static Application* getSingletonPtr(void);

void enterMainLoop(void);
};

So jetzt kann ich das aber umgehen, indem ich nicht diese Headerdatei im Wrappercode inkludiere, sondern die Klasse direkt dort definiere, aber wie bei einem Interface nur die Methoden etc. definiere, auf die ich auch von Ruby aus zugreifen müsste. Das würde wie folgt aussehen:
class Application
{
public:
Application(void);
virtual ~Application(void);

void enterMainLoop(void);
};

Dabei fällt die Abhängigkeit von Ogre.h weg (Die zugrundeliegende Grafikengine interessiert mich in Ruby auch überhaupt nicht) und die Header-Dateien, welche später aufgrund der Makros Probleme bereiten fallen so auch weg.

Allerdings wüsste ich ganz gerne, ob es überhaupt legal ist, sozusagen externe Klassen zu definieren, aber dabei nur einen Teil der Definition zu berücksichtigen?

ScottManDeath
2005-05-05, 18:27:00
AFAIK muss eine Definition eindeutig sein. Wenn sie mehrmals vorkommt, so muss sie identisch sein. Mach doch einfach ein Interface für deine Application. Deine App leitet von diesem Interface ab. Dann muss der Teil der mit den Ruby Makros zu kämpfen hat nur IApplication.h includen, deine Klassenimplementation ist davon dann unberührt und muss dann den Ruby kram nicht includen


// IApplication.h
class IApplication
{
public :
virtual ~IApplication() {};
virtual void enterMainLoop() = 0;
... und alles was sonst noch so nötig ist
}




//application.h
#include "IApplication.h"
#include <Ogre.h>

class Application : public Ogre::Singleton<Application>, public IApplication
{
public:
Application(void);
virtual ~Application(void);

static Application& getSingleton(void);
static Application* getSingletonPtr(void);

virtual void enterMainLoop(void);
};

DerTod @ GastAcc :)
2005-05-05, 22:37:42
AFAIK muss eine Definition eindeutig sein. Wenn sie mehrmals vorkommt, so muss sie identisch sein.
Vielen Dank, wieder was dazugelernt :) Werde es dann wohl mit einem Interface machen.
Ging mir primär darum, ob es anders erlaubt / möglich gewesen wäre, ohne dass man später Probleme damit bekommt.

Gnafoo
2005-05-05, 22:57:43
Wobei mir fällt grad auf, dass das ohne weiteres so nicht gehen würde. SWIG würde nämlich (soweit ich das sehe) versuchen eine Instanz des Interfaces zu erstellen, was aufgrund der abstrakten Methoden nicht geht.
Sieht wohl so aus, als ob ich noch etwas im SWIG-Manual suchen muss. :-|

Edit: Ich habe gerade auf der suche nach einer eleganten Lösung Folgendes im SWIG-Manual gefunden:

---------------- SNIP ----------------
Since SWIG is still limited in its support of C++, it may be necessary to use partial class information in an interface file. However, since SWIG does not need the entire class specification to work, conditional compilation can be used to comment out problematic parts. For example, if you had a nested class definition, you might do this:

class Foo {
public:
#ifndef SWIG
class Bar {
public:
...
};
#endif
Foo();
~Foo();
...
};


Also, as a rule of thumb, SWIG should not be used on raw C++ source files.
---------------- SNAP ----------------

Die nehmen hier also auch gezielt Teile der Definition heraus. (Wobei das Beispiel hierfür nicht ganz eindeutig ist, weil die eine gekapselte Klasse rausnehmen)

Gnafoo
2005-05-06, 00:38:31
So ich glaube das Thema hat sich erledigt. Falls es jemanden interessiertm die Lösung sieht nun wie folgt aus: SWIG generiert ja letztendlich eine große C++-Datei. Diese wrappt den C++-Code in eine Library, die von Ruby aus genutzt wird.

Das Problem mit den Macros besteht immer dann, wenn ich ruby.h vor Ogre.h inkludiere. Ruby.h definiert nämlich u.a. so nette Makros wie close, open, tell etc. Das führt unter anderem in "iostream" oder bei anderen Klassen zu Problemen, wenn diese Methoden mit diesen Namen definieren. (ruby.h ist eigentlich für C und nicht C++ gedacht, daher wahrscheinlich die Problematik)

Anders herum gibt es keine Probleme, wenn Ogre.h vor ruby.h inkludiert wird. Hier sind dann die Definitionen / der Code von Ogre (oder anderen Header-Files davor) von den Macros aus ruby.h unabhängig. So sind Deklaration / Code und Wrapper-Code auf die Makros bezogen eher getrennt, so wie es sein sollte.

Nun ist es auf den ersten Blick aber recht fest in SWIG verankert, dass zunächst ruby.h inkludiert wird, bevor etwas anderes geschieht.
Diesen Aufbau liest SWIG wiederum aus eigenen Dateien (rubyhead.swg). Der Trick ist jetzt allerdings, dass man eben die Funktionalität jener Datei überschreiben kann, indem man im Verzeichnis, in dem die übrigen Interface-Dateien liegen (SWIG nutzt diese um den Code zu generieren) eine eigene Version bereitstellt. In dieser kann man dann die gewünschten Header-Dateien vor "ruby.h" inkludieren.

Die Header Guards der Header-Files sorgen dann dafür, dass die Header nicht erneut inkludiert werden und das Problem noch einmal auftritt. So funktioniert es jetzt tadellos.