C++ Klassen in BlitzMax nutzen

Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Neue Antwort erstellen

Vertex

Betreff: C++ Klassen in BlitzMax nutzen

BeitragSa, Okt 25, 2008 16:59
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich musste feststellen, dass es nicht möglich ist, C-Strukturen (struct) als BlitzMax-Typ (Type) abzubilden. Das die Adressen der Fields des Types mit der der Member von der Struct übereinstimmen, ist reine Willkür und führt meistens zu Bad Refs (beim Zugriff auf Strings und weiteren BMax Objekten) und anderen, unbestimmten Ergebnissen.

Arrow Zugriff auf C-Strukturen nur mittels Funktionen

Mein nächster Ansatz ging daher gleich über C++. Ich möchte hier ein Beispiel zeigen zum allgemeinen Umgang mit C++ Klassen, da das Beispiel aus der Doku (Language > Advanced topics > Interfacing with C) nicht alles beantwortet.

Zu Beschränkungen zählen (teils aus der Doku)
Arrow Methoden müssen virtual deklariert sein (bis auf den Konstruktor natürlich).
Arrow Zugriff auf Konstruktor und Destruktor nicht möglich. Es müssen daher Create- und Destroy-Funktionen exportiert werden.
Arrow Externe Typen können andere externe Typen erweitern aber nicht BlitzMax Standardtypen. BlitzMax Typen können nicht externe Typen erweitern.
Arrow Objekte von externen Typen können nicht zu BlitzMax-Object gecastet werden.
Arrow Zugriff auf statische Methoden und Felder nur über exportierte Funktionen möglich.

Es bietet sich daher an, einen Wrappertyp in BlitzMax zu erstellen, um den gewohnten Zugriff dem Anwender zu erlauben.

Im Beispiel gibt es die Klasse CTest mit folgenden Eigenschaften:
Code: [AUSKLAPPEN]
- Konstruktor CTest
- Destruktor ~CTest
- Klassenvariable someGlobal
- Klassenfunktionen getSomeGlobal, setSomeGlobal
- Feld someText
- Methoden getSomeText, setSomeText
- Methode doSomething


Um den Zugriff auf die Klasse zu exportieren gibt es folgende Funktionen:
Code: [AUSKLAPPEN]
- CreateCTest erstellt neues Objekt der Klasse CTest (auf dem Heap?)
- DestroyCTest gibt den Speicher für das Objekt wieder frei
- CTest_getSomeGlobal gibt Klassenvariable someTest zurück
- CTest_setSomeGlobal setzt someTest

Diese Funktionen müssen über extern "C" exportiert werden, sonst werden die Parameter an den Funktionsaufruf in falscher Reihenfolge übergeben?

Damit der Anwender ein Objekt wie gewohnt über New instantiieren kann, und auf die Klassenfunktionen ohne Zusatzfunktionen zugreifen kann, wird daher der Typ TTest in BlitzMax deklariert. Dieser hat ein Feld namen "instance" . Im Konstruktor von TTest wird die Instanz con CTest über CreateCTest angelegt.

Zum Beispiel:

test.hpp
Code: [AUSKLAPPEN]
#ifndef TEST_HPP
#define TEST_HPP

#include <string>
#include <iostream.h>

using namespace std;

class CTest
{
private:
   static int someGlobal;
   string someText;
   
public:
   CTest();
   virtual ~CTest();

   static int getSomeGlobal();
   static void setSomeGlobal(int someGlobal);

   virtual const char *getSomeText();
   virtual void setSomeText(char *someText);
   virtual void doSomething();
};

extern "C" {
   CTest *CreateCTest();
   void DestroyCTest(CTest *test);
   int CTest_getSomeGlobal();
   void CTest_setSomeGlobal(int someGlobal);
}

#endif


test.cpp
Code: [AUSKLAPPEN]
#include "test.hpp"

int CTest::someGlobal = 54321;

CTest::CTest() {
   someText = "";
}

CTest::~CTest() {
}

int CTest::getSomeGlobal() {
   return someGlobal;
}

void CTest::setSomeGlobal(int someGlobal) {
   CTest::someGlobal = someGlobal;
}

const char *CTest::getSomeText() {
   return someText.c_str();
}

void CTest::setSomeText(char* someText) {
   this->someText = someText;
}

void CTest::doSomething() {
   cout << "CTest::doSomething()" << endl;
}

extern "C" {
   CTest *CreateCTest() {
      return new CTest;
   }

   void DestroyCTest(CTest *test) {
      delete test;
   }

   int CTest_getSomeGlobal() {
      return CTest::getSomeGlobal();
   }

   void CTest_setSomeGlobal(int someGlobal) {
      CTest::setSomeGlobal(someGlobal);
   }
}


test.bmx
Code: [AUSKLAPPEN]
Framework BRL.Blitz

Import "test.cpp"
Extern
   Type CTest
      Method _pad1()
      Method _pad2()
      Method getSomeText$z()
      Method setSomeText(someText$z)
      Method doSomething()
   End Type
   
   Function CreateCTest:CTest()
   Function DestroyCTest(test:CTest)
   Function CTest_getSomeGlobal:Int()
   Function CTest_setSomeGlobal(someGlobal:Int)
End Extern

Type TTest
   Field instance : CTest
   
   Method New()
      instance = CreateCTest()
   End Method
   
   Method Delete()
      If instance <> Null Then DestroyCTest(instance)
   End Method
   
   Function getSomeGlobal:Int()
      Return CTest_getSomeGlobal()
   End Function
   
   Function setSomeGlobal(someGlobal:Int)
      CTest_setSomeGlobal(someGlobal)
   End Function
   
   Method getSomeText:String()
      If instance = Null Then Throw New TNullObjectException
      Return instance.getSomeText()
   End Method
   
   Method setSomeText(someText:String)
      If instance = Null Then Throw New TNullObjectException
      instance.setSomeText(someText)
   End Method
   
   Method doSomething()
      If instance = Null Then Throw New TNullObjectException
      instance.doSomething()
   End Method
End Type

Local test:TTest

DebugLog TTest.getSomeGlobal()
DebugLog TTest.setSomeGlobal(12345)
DebugLog TTest.getSomeGlobal()

test = New TTest

DebugLog test.getSomeText()
test.setSomeText("Some Text")
DebugLog test.getSomeText()

test.doSomething()


Wer weitere Tipps zum Thema C/C++ mit BlitzMax hat, immer her damit! Ich habe im Übrigen nicht BBInt und BBString verwendet, da mir der GC von BlitzMax nicht ganz schlüssig ist.

mfg olli
vertex.dreamfall.at | GitHub

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group