Über unsMediaKontaktImpressum
Ulrich Stein 25. Oktober 2016

Objektorientierte Programmierung mit MATLAB

MATLAB®, ein Programmpaket mit einer Vielzahl numerischer Verfahren, objektorientierte Programmierung (nicht gerade das allerneueste "Paradigma") und das Problem: Wie bringe ich junge Menschen dazu, die Grundzüge des Programmierens zu erlernen? Mit diesen Themen beschäftigt sich dieser Artikel. Ich möchte von einem Weg berichten, der etwas vom normalen Programmierkurs abweicht. Ein etwas anderer Weg zur objektorientierten Programmierung. Ein Weg, den ich und meine Kollegen in Hamburg seit gut zehn Jahren beschreiten und der sich, allen frühen Zweiflern und Unkenrufen zum Trotz, nicht als Sackgasse erwiesen hat.

Vorspiel

Objektorientierte Programmierung - lohnt es sich denn überhaupt noch, darüber einen Artikel zu schreiben? Beziehungsweise, einen Beitrag zu diesem Thema zu lesen?

Als ich, Mitte der 1970er Jahre, meine erste Programmiersprache erlernte (ALGOL 60), da war ich besessen von dem Gefühl, endlich auch mal Kontakt zu einer dieser geheimnisvollen Maschinen aufnehmen zu können - zu einer TR 440, ein Großrechner der Firma Telefunken - dank dem Motto: "Deutsche Rechner an deutschen Universitäten!". Dieses Gefühl von Macht, wenn ich das Ungetüm bezwungen hatte. Wenn mir die Maschine auf Endlospapier das Ergebnis ausdruckte. Zwei Stunden, nachdem ich dem Operator den Lochstreifen mit dem Programm übergeben hatte - das Ergebnis, die Zahl 42.

Seit damals hat sich jedoch einiges verändert. Die Autos wurden größer und die Computer kleiner - was an sich nicht verwerflich ist. Aber irgendwie ging das Gefühl von Macht verloren. Meine damaligen Programme schafft inzwischen schon der einfachste programmierbare Taschenrechner. Und wer hat heute noch Ehrfurcht vor einem Taschenrechner?

Vor diesem Problem stand ich vor dreizehn Jahren, als ich an der HAW Hamburg meinen ersten Programmierkurs anbot. Programmiercode, geschrieben in der Sprache C, der auf einem MS-Windows-Rechner kompiliert und gelinkt wurde - beides Aktionen, die den Studenten mehr Probleme bereiteten als das Schreiben der sechs Programmzeilen. Und dann auch noch der Programmaufruf im Konsolenfenster. Wenn alles gut gelaufen war, erschien dort (nach weniger als einer Sekunde) das Ergebnis, weiß auf schwarz - nein, nicht die Zahl 42, sondern der Text "Hello, world". Soviel Ehrfurcht vor Brian Kernighan und Dennis Ritchie [1] musste sein!

Sehr beeindruckt waren meine Studenten aber nicht. Wahrscheinlich hatten die meisten von ihnen zuhause schnellere Rechner als wir in den Übungsräumen an der Hochschule. Und ihre Videospiele zeigten Interessanteres als die weißen Schriftzeichen, die ihr erstes C-Programm produzierte.

Unsere Informatikkurse, angesiedelt in den ersten beiden Semestern des Maschinenbau-Studiums, blieben unbeliebt. Was auch daran lag, dass C-Kenntnisse im weiteren Verlauf des Studiums (und meist auch im Ingenieuralltag in der Industrie) nicht benötigt wurden. Man brauchte die beiden Scheine und machte anschließend drei Kreuze.

Hier kam, im Jahr 2005, das Programm MATLAB ins Spiel. Wir haben unseren Programmier-Kurs von C auf MATLAB umgestellt - mit der Vorgabe, möglichst alles, was Kernighan und Ritchie darlegen, mit Hilfe von MATLAB zu lehren. Bei den Zeigern haben wir versagt!

MATLAB

Das Softwarepaket MATLAB der Firma Mathworks [2] gehört weltweit zu den bekanntesten Tools zur Berechnung und Simulation komplexer mathematischer und technischer Probleme sowie zur grafischen Darstellung der Ergebnisse. In der Industrie und an Hochschulen wird MATLAB für vielfältige Aufgaben eingesetzt, insbesondere in der Regelungstechnik und der technischen Mechanik. Zusätzlich zum Basismodul ist eine ganze Reihe von Erweiterungen für MATLAB erhältlich, die so genannten Toolboxen™. Dazu gehört Simulink®, eine grafische Oberfläche, mit der man interaktiv Systeme modellieren und simulieren kann. An numerischen Verfahren bietet MATLAB nahezu alles, was das Herz begehrt: Angefangen von Standardverfahren, wie der Lösung linearer Gleichungssysteme, Nullstellenberechnung für beliebige Funktionen oder numerischer Integration, über Solver für Differentialgleichungen oder symbolisches Rechnen mit Hilfe des Moduls MuPAD®, bis zu sehr speziellen Anwendungen, wie der Simulation von Verbrennungsmotoren oder der Ansteuerung von Robotern.

Die Funktionalität von MATLAB kann auf zwei Arten genutzt werden: Zum einen als interaktive Berechnungs- und Simulationsumgebung und zum anderen über den Aufruf von selbst geschriebenen MATLAB-Funktionen, die die numerischen Methoden von MATLAB benutzen.

Die Programmiersprache [3] von MATLAB verwendet weitgehend die bekannte mathematische Notation. Kontroll- und Datenstrukturen sind ähnlich definiert wie in der Sprache C. Es gibt jedoch kleinere Unterschiede, wie die Verwendung des Zeichens "~" für die Negation (anstelle der C-Notation "!") und die Kennzeichnung eines Kommentars mit einem einleitenden %-Zeichen.

Variablen werden in MATLAB nicht explizit deklariert. Der Datentyp einer Variablen wird erst durch die Initialisierung mit einem Wert eindeutig festgelegt, z.B. "rot = uint8(255)", wobei die primären Datentypen im Großen und Ganzen denen von C entsprechen, also z.B. double und char. Für selbst deklarierte Typen gilt dies ebenso. Beispielsweise erzeugen Sie ein Objekt meiner Rechteck-Klasse ShRect durch folgenden Konstruktor-Aufruf, der die Werte für Breite (10) und Höhe (8) übernimmt: "obj = ShRect(10,8)". MATLAB hat dem Anwender aber einige "Arbeit" abgenommen und erledigt gewisse Aufgaben automatisch, falls der Anwender dies nicht explizit selbst vornimmt. Wenn Sie zum Beispiel eine Variable mit einer Zahl initialisieren, ohne den Datentyp anzugeben, wie bei "y = 8", dann erhält die Variable, hier y, automatisch den Typ double. Analoges gilt bei der Initialisierung mit einem Text, wie bei "t = 'Hello, world'", wo der Typ char (bzw. char-Array) vergeben wird.

Funktionen (und damit auch die Methoden einer Klasse) sind in MATLAB jedoch nicht typisiert, d.h. der Funktionskopf enthält nur die formalen Parameter, nicht aber deren Datentyp. Der Funktionskopf startet mit dem Schlüsselwort function. Der Funktionsrumpf geht bis zum abschließenden Schlüsselwort end. Eine Funktion rechteck, die aus den übergebenen Werten a und b (für die Breite und Höhe) die Rechteckfläche f = a*b berechnet, sieht in MATLAB wie folgt aus:

function f = rechteck(a,b)
f = a*b;
end

Durch die Deklaration "f = " wird festgelegt, was die Funktion zurückgibt - also auch hier ohne Datentyp und auch ohne eine Anweisung, wie "return(f)".

Wenn Sie eine Typüberprüfung der Eingangswerte wünschen, dann müssen Sie dies am Anfang des Funktionsrumpfes explizit selbst mittels der Funktion isa ("ist ein" = besitzt den Typ) durchführen. Wenn Sie für die Eingangswerte und die Rückgabe den varargs-Mechanismus verwenden, können Sie mittels der selbst durchgeführten Typüberprüfung sogar mehrere Methoden mit demselben Namen aber unterschiedlicher Signatur realisieren - was so in MATLAB nicht direkt vorgesehen ist.

Beim Aufruf einer Funktion wird der Programm-Code zeilenweise interpretiert. Als Syntax-Checker ist eine LINT-Variante integriert, die Sie bereits beim Editieren unterstützt und die Sie, zumindest bei größeren Programmen, vor der Programmausführung explizit verwenden sollten. Es gibt aber auch die Möglichkeit, den Code (mit Hilfe eines Zusatzmoduls) zu kompilieren, wobei der Syntax-Check automatisch aufgerufen wird. Das direkt ausführbare Programm sollte dann um einiges schneller ablaufen.

Der Basis-Datentyp in MATLAB ist die Matrix, also ein ein- oder mehrdimensionales Feld. Matrizenrechnungen sind deshalb eine der Stärken von MATLAB. Sie müssen die Länge der Felder vorher nicht explizit deklarieren. Beim Initialisieren der benötigten Komponente passt MATLAB selbst die Feldlänge an. Bei größeren Feldern empfiehlt es sich jedoch, die Feldlänge vor dem ersten Zugriff festzulegen, da auch MATLAB für die (automatisch vorgenommene) Re-Alloziierung des Speicherplatzes Zeit braucht.

In MATLAB gibt es weder Zeiger noch Referenzen - jedenfalls nicht für Variable mit den primären Datentypen. Durch die Einführung der Handle-Klassen verhalten sich deren Objekte jedoch sehr ähnlich wie Referenzen. Außerdem gibt es Zeiger auf Funktionen (Function-Handles), was beispielsweise beim Lösen von Anfangswertproblemen für gewöhnliche Differentialgleichungen (ode = ordinary differential equations) mittels eines ODE-Solvers Anwendung findet, hier für den Solver ode45 für ein Runge-Kutta (4,5)-Verfahren:

sol = ode45( @fun, [0,2], x0 );

Der Aufruf ode45 erhält als ersten Wert den Zeiger auf die Funktion fun, durch die die Differentialgleichung definiert. ist. Mit "@fun" wird also der Zeiger auf die Funktion fun bestimmt. Die weiteren Übergabewerte legen das Zeitintervall (0 bis 2 Sekunden) und den Anfangswert x0 fest.

Zur prozeduralen Programmierung mit MATLAB gibt es eine ganze Reihe von Online-Tutorials und einige Lehrbücher, beispielsweise auch ein Buch von mir [4]. Deshalb werde ich in diesem Beitrag auf dieses Thema nicht näher eingehen.

Objektorientierte Programmierung (OOP)

Weniger bekannt sind jedoch die OOP-Möglichkeiten von MATLAB. Das liegt zum Teil an der Vorgeschichte: Mit der OOP-Variante, die bis zur Version MATLAB 2007 implementiert war, konnte auch ich mich nicht anfreunden. Sie war zu umständlich, unnötig kompliziert und recht unvollständig. Deshalb habe ich die Umstellung auf die aktuelle Variante, im Jahr 2008, auch vollkommen verschlafen.

Ich blieb lange Zeit skeptisch, ob man mit MATLAB vernünftig objektorientiert programmieren kann. Denn im Vergleich mit anderen Programmiersprachen, wie z.B. C++ [5] oder Java [6], fehlten in MATLAB doch ein paar Dinge, beispielsweise die Möglichkeit, mehrere Methoden mit demselben Namen aber unterschiedlicher Signatur zu deklarieren. Dies ist in MATLAB nicht vorgesehen. Aber hierfür – und auch für andere fehlende Bereiche – kann man sich recht einfach einen vernünftigen Workaround bauen. Und je länger ich mich mit der OOP-Funktionalität in MATLAB beschäftigte, desto mehr hat sie mich überzeugt.

Ich weiß, in diesem kurzen Artikel kann ich Ihnen keine vollständige Einführung in die OOP-Funktionalität von MATLAB bieten - um auch Sie zu überzeugen. Aber ich werde Ihnen wenigstens einen Teil davon zeigen. Und viel mehr schaffe ich auch in meiner Anfängervorlesung nicht.

Klassendefinition

Beginnen wir mit der Definition einer Klasse. In MATLAB startet hierzu der Programm-Code mit dem Schlüsselwort classdef, gefolgt vom Namen der Klasse, und wird mit dem Bezeichner end abgeschlossen. Innerhalb des classdef-Blocks gibt es (optional) verschiedene Sektionen:

  • properties: Objekt-Variablen mit den Eigenschaften der Klasse.
  • methods: Methoden der Klasse, u.a. Konstruktor und evtl. Destruktor.
  • events: Ereignisse, die von Objekten der Klasse ausgelöst werden können.
  • enumeration: Aufzählungen, d.h. eine Liste von konstanten Werten.

Das allgemeine classdef-Gerüst für eine Klasse mit dem Namen Classname sieht wie folgt aus:

Listing classdef-Block:

classdef Classname
properties % Sektion Eigenschaften
x = 0;
...
end % properties-Sektion

methods % Sektion Methoden
function obj = Classname(...) % Konstruktor
obj.x = ...
...
end
...
function delete( obj ) % Destruktor
...
end
end % methods-Sektion

events % Sektion Ereignisse
...
end % events-Sektion

enumeration % Sektion Aufzählungen
...
end % enumeration-Sektion
end % classdef-Block

Die Kommentare hinter den %-Zeichen sind nicht notwendig. Sie dienen nur der Übersicht.

Der Konstruktor-Aufruf "c = Classname(...)" erzeugt, wie üblich, ein Objekt, hier mit dem Namen c, und er kann auch bereits Daten an das Objekt übergeben, hier angedeutet durch "(...)". Diese Daten speichert man typischerweise in den Objekt-Variablen, im classdef-Block als Beispielzuweisung "obj.x = ..." eingetragen.

Auf die Eigenschaften und Methoden einer Klasse greift man, wie von C++ gewohnt, über den Punktoperator zu, beispielsweise "wert = c.x" zum Auslesen des x-Wertes oder "c.delete()" als Destruktor-Aufruf.

Datenkapselung

Der Zugriff auf Eigenschaften und Methoden kann durch Attribute eingeschränkt werden. Hierbei verwendet MATLAB die in C++ üblichen Bezeichner public, private und protected. Soll beispielsweise die Eigenschaft xpublic sein und die Eigenschaft y protected, dann müssen sie in zwei getrennten Sektionen im classdef-Block erscheinen:

Listing Datenkapselung:

classdef Classname
properties (Access = public) % public Eigenschaften
  x = 0;
 end % public properties

properties (Access = protected) % protected Eigenschaften
y = 0;
 end % protected properties

 ...
end  % classdef-Block

Die Eigenschaft public ist voreingestellt. Deshalb muss dieses Attribut nicht zwingend angegeben werden.

Vererbung

Soll eine Klasse von einer Basisklasse abgeleitet sein, wird dies in der classdef-Vereinbarung durch das Zeichen "<" angegeben, z.B.

classdef Childclass < Parentclass

bzw. bei mehreren Basisklassen durch das zusätzliche Verknüpfungszeichen "&":

classdef Childclass < Parent1 & Parent2

Im Konstruktor der abgeleiteten Klasse wird zunächst ein Objekt der Basisklasse erzeugt (evtl. mit der Übergabe von Daten), bevor die Eigenschaften der abgeleiteten Klasse, hier x, belegt werden können:

function obj = Childclass(...) % Konstruktor
obj@Parentclass(...);
 obj.x = ...
 ...
end

Eine abgeleitete Klasse (child = Kind) erbt die Eigenschaften und Methoden ihrer Basisklasse (parent = Vater), solange diese als public oder protected und nicht als private gekennzeichnet sind. Falls die Basisklasse selbst von weiteren Klassen abgeleitet ist, werden auch deren Eigenschaften und Methoden vererbt.

Polymorphie

Abgeleitete Objekte haben den Typ der Basisklasse geerbt. Sie sind damit nicht nur Objekte der eigenen Klasse, sondern ebenfalls Objekte der Basisklasse. Ein Objekt meiner Rechteck-Klasse ShRect ist gleichzeitig auch ein Objekt der Basisklasse Shape. Umgekehrt gilt das jedoch nicht. Ein Objekt vom Typ Shape ist nicht automatisch auch vom Typ ShRect. Die Zugehörigkeit zu einer Klasse kann, wie bei den primären Datentypen, mit der Funktion isa getestet werden.

Die Polymorphie ist in MATLAB genauso implementiert wie in anderen OOP-Sprachen auch: So kann ein Kind, also das Objekt einer abgeleiteten Klasse, die Eigenschaften und Methoden seiner Basisklasse verwenden, solange diese public oder protected sind. Die Kindklasse kann die geerbten Methoden aber auch überschreiben, das heißt: Das Kind definiert eine eigene Implementierung dieser Methode, deren Signatur aber bereits in der Basisklasse deklariert wurde.

Erst zur Laufzeit wird entschieden, welche Methode zum Einsatz kommt, nämlich die oberste in der Klassenhierarchie. Möchte man in einer abgeleiteten Klasse, z.B. in ShRect, auf eine Methode der Basisklasse zugreifen, so erreicht man dies durch Angabe des Namens der Vaterklasse hinter dem eigentlichen Methodenaufruf, beispielsweise zum Aufruf die Methode disp der Vaterklasse Shape in einer Methode der Kindklasse ShRect durch:

obj.disp@Shape();

Eine Klasse wird zur abstrakten Klasse, wenn es in ihr mindestens eine Methode gibt, deren Funktions-Kopf (Signatur) zwar als Schnittstelle deklariert ist, wo aber der Funktions-Rumpf (Implementierung) fehlt. Dies muss dann in der abgeleiteten Klasse nachgeholt werden, damit Kind-Objekte erzeugt werden können.

Eine Klasse kann auch beliebige Methoden anderer Klassen überladen, indem sie selbst eigene Methoden mit demselben Namen definiert. Beispielsweise besitzt MATLAB eine eigene Methode disp, die zur Darstellung von Zahlen und Text auf dem Bildschirm gedacht ist. Ich habe diese Methode für meine Klasse Shape überladen, um die Eigenschaften eines Shape-Objekts anzuzeigen. MATLAB erkennt beim Aufruf von disp am Typ des Objekts, welche Implementierung gemeint ist.

Es gibt auch eine Reihe von (mathematischen) Operatoren, wie "+", "-", "*", die von selbst definierten Klassen überladen werden können. Hierfür sind spezielle Methodennamen reserviert, wie beispielsweise mtimes für den Multiplikations-Operator "*". Ich habe für Objekte meiner Rechteck-Klasse ShRect die Multiplikation mit einer Zahl definiert, die das Rechteck um diesen Faktor streckt, z.B. eine Streckung um 5 für das ShRect-Objekt r:

>> r = ShRect(3,4);
>> r * 5;

Handle-Klassen

Zugegeben, ich war in den obigen Zeilen ein klein wenig ungenau. Einige der erwähnten Klasseneigenschaften gelten in MATLAB nur für Handle-Klassen.

MATLAB kennt zwei Arten von Klassen: Value-Klassen und Handle-Klassen. Value-Klassen enthalten hauptsächlich Datenwerte (values) und sind für abstrakte Objekte gedacht. Handle-Klassen sind abgeleitet von der (abstrakten) Klasse handle. Objekte einer Handle-Klasse sind keine unabhängigen Datensätze, sondern Referenzen auf ein eindeutiges, reales Objekt, zum Beispiel auf geometrische Objekte in einer Zeichnung, die eindeutig identifiziert werden können. Von Handle-Klassen abgeleitete Klassen sind selbst wieder Handle-Klassen, erben also alle Handle-Methoden.

Die einfachen Value-Klassen besitzen weder Destruktor noch Ereignisse. Und beim Ändern von Eigenschaften (mit Hilfe von Methoden) müssen die Methoden von Value-Klassen das veränderte Objekt an den Aufrufer zurückgeben, z.B. beim Aufruf der Multiplikations-Methode "*" (mit der Zahl 5) für ein Objekts d der Datenklasse Data:

>> d = Data([2,3,4]);
>> d = d * 5;

Lässt man die Zuweisung "d = ..." weg, dann wird das Objekts d zwar (per Pass-by-Value) an die Methode mtimes übergeben, aber das veränderte Objekt wird nicht zurückgeliefert.

Für Handle-Klassen entfällt die Zuweisung nach einer Veränderung, da in diesem Fall die Referenz auf das Objekt übergeben wird, wie wir es bei der Multiplikation eines Rechteck-Objekts gesehen haben.

Der Destruktor einer Handle-Klasse besitzt den Namen delete. Die Methode delete ist bereits in der Basisklasse handle definiert und kann in den abgeleiteten Klassen überschrieben werden, um weitere Aufräumarbeiten vorzunehmen. Der Destruktor zu einem Objekt wird automatisch aufgerufen, wenn die letzte Referenz auf dieses Objekt gelöscht wurde. Ist die zugehörige Klasse bereits von mehreren weiteren Handle-Klassen abgeleitet, dann werden nacheinander auch alle Destruktoren der tiefer liegenden Klassen aufgerufen.

Wenn Sie ein Objekt einer Handle-Klasse einer weiteren Variablen zuweisen, dann wird dadurch kein neues, unabhängiges Objekt erzeugt, sondern nur eine weitere Referenz, z.B.:

>> r1 = ShRect(3,4);
>> r2 = r1;
>> r2 * 5;

Eine Veränderung der Kopie, hier r2 um den Faktor 5, ändert deshalb automatisch auch das Ursprungsobjekt der Handle-Klasse, hier r1.

Möchten Sie eine unabhängige Kopie des Objekts einer Handle-Klasse, dann benötigen Sie einen Kopierkonstruktor (Copy Constructor). Ein normaler Konstruktor erzeugt ein Objekt der Klasse und initialisiert dieses Objekt mit irgendwelchen Daten. Ein Kopierkonstruktor erzeugt ebenfalls ein neues Objekt dieser Klasse, übernimmt aber die Daten von einem bestehenden Objekt, das dem Konstruktor beim Aufruf übergeben wird. In MATLAB würde das für ein Objekt der Klasse ShRect wie folgt aussehen:

>> r1 = ShRect(3,4);
>> r2 = ShRect(r1);
>> r2 * 5;

Beim ersten Aufruf des Konstruktors ShRect wird eine neues Objekt r1 erzeugt und mit den übergebenen Daten (3,4) initialisiert. Beim zweiten Aufruf wird dem (Kopier-)Konstruktor das bereits bestehende Objekt r1 übergeben und damit ein unabhängiges Objekt r2 erzeugt, das die Daten von r1 als Kopie bekommen hat.

Soweit die Theorie - für eine Klasse implementiert man zwei Konstruktoren (also zwei Methoden mit dem Namen der Klasse), die sich durch ihre Argumentliste unterscheiden.

MATLAB erlaubt jedoch nicht, für eine Klasse zwei unterschiedliche Methoden mit demselben Namen zu definieren. Das gilt auch für die Konstruktoren.

Hier behelfe ich mich mit folgendem Workaround: Ich definiere die Konstruktor-Methode mit einer variablen Argumentliste (varargs-Mechanismus) und verzweige im Konstruktor selbst in unterschiedliche Implementierungen, je nach Typ der übergebenen Daten.

Zu Beginn wird in beiden Fällen ein neues Shape-Objekt erzeugt, mittels der Anweisung obj@Shape(0,0);. Dann wird mit isa der Typ des ersten übergebenen Arguments überprüft (varargin{1}). Ist dies ein ShRect-Objekt, dann übernimmt das neue Objekt dessen Daten, hier z.B. die Länge obj1.len, etc. Im anderen Fall wurden die Rechteck-Daten beim Konstruktor-Aufruf explizit angegeben und werden dann aus der Argumentliste varargin an das neue Objekt übergeben, im Beispiel wieder die Länge obj.len:

Listing Konstruktor und Kopierkonstruktor der Klasse ShRect:

function obj = ShRect(varargin)
obj@Shape(0,0);
 obj1 = varargin{1};
 if( isa( obj1, 'ShRect' ) ) % Kopierkonstruktor
  obj.len = obj1.len;
...
else
    obj.len = varargin{1};
...
end
end

Mit Hilfe von Handle-Klassen lassen sich problemlos verkettete Listen bilden, an deren Knoten Objekte von anderen Handle-Klassen hängen. In meinem OOP-Buch zu MATLAB [7] habe ich dies anhand einer Grafik-Liste gezeigt.

Weiteres

MATLAB bietet noch einiges mehr an OOP-Funktionalität: Sie können das Verhalten von Eigenschaften und Methoden durch weitere Attribute beeinflussen, beispielsweise konstante Eigenschaften durch Angabe von Constant oder statische Methoden durch Angabe von Static. Für Handle-Klassen können Ereignisse (events) definiert werden, auf die ein Objekt reagiert, falls es auf das Ereignis als Listener achtet. Des Weiteren kann eine Klasse eine Aufzählung (enumeration) enthalten, also eine Liste von konstanten Werten, beispielsweise Kürzel für die Wochentage. Für größere Projekte bietet es sich an, die Klassen in Paketen (packages) zu bündeln. Hierdurch können auch Namensbereiche (namespaces) realisiert werden. Für die Fehlerbehandlung existiert eine eigene Klasse MException, von der man weitere Klassen für ein explizites Fehlerhandling mittels try und catch ableiteten kann.

Vergleich mit C++

Im Vergleich zu anderen OOP-Sprachen besitzt MATLAB einige Besonderheiten. Gewisse Sprachelemente fehlen. Auf der anderen Seite bietet MATLAB spezielle Erweiterungen, mit deren Hilfe man sich weiterhelfen kann.

Der Hauptunterschied zu C++ und Java liegt im fehlenden Typ-Check von MATLAB. Es ist deshalb nicht möglich, verschiedene Methoden mit demselben Namen aber unterschiedlicher Signatur zu definieren. Als Workaround dient hier der varargs-Mechanismus, mit dem Sie innerhalb einer Methode zu unterschiedlichen Funktionalitäten verzweigen können, wie beim Kopierkonstruktor gezeigt.

MATLAB kennt weder Referenzen noch Zeiger. Die Übergabe von Daten an eine Unterfunktion erfolgt immer per Pass-by-Value. Andererseits gibt es in MATLAB die Handle-Klassen. Handles verhalten sich ähnlich wie Referenzen.

MATLAB kennt keine Templates, also die Übergabe eines Datentyps an eine Methode zur Laufzeit. In diesem Fall hilft der fehlende Typ-Check von MATLAB. Man muss bei der Verwendung einer Variablen in MATLAB deren Typ gar nicht kennen. Mittels der Funktion isa kann man den Typ zur Laufzeit ermitteln.

In C++ gibt es das Konzept der friend-Klassen. Ein Objekt einer "befreundeten" Klasse kann, wie Objekte von abgeleiteten Klassen, auf geschützte (protected) Eigenschaften zugreifen. In MATLAB erreicht man ein ähnliches Verhalten, indem man den Zugriff für spezielle Klassen erlaubt.

Dies geschieht durch folgende Vereinbarung:

methods ( Access = {?ClassName1, ?ClassName2, ...} )

Fazit

Die (interpretierte) Programmiersprache von MATLAB ist nicht dafür gedacht, größere Software-Projekte mit vielen eigenen Berechnungsroutinen durchzuführen. Für solche Aufgaben sollte man kompilierte Programme verwenden, die in der Regel um einiges schneller ablaufen.

Auf der anderen Seite stellt MATLAB eine Vielzahl von numerischen Verfahren zur Verfügung, die auch mit sehr großen Datenmengen sehr effektiv arbeiten. Diese Verfahren sind als Bibliotheksfunktionen nämlich nicht in der Programmiersprache von MATLAB implementiert, sondern in C. Wenn man MATLAB primär zur Steuerung der Datenflüsse für diese Verfahren verwendet und nicht für eigene Berechnungsmethoden, dann kann man mit MATLAB auch größere Aufgaben recht elegant erledigen.

Es gibt außerdem weitere, mächtige Programmsysteme, die mit MATLAB kombinierbar sind: Zum Beispiel die Software-Plattform COMSOL Multiphysics® [9], deren Ansteuerung und FEM-Datenanalyse in MATLAB integriert werden kann. Oder die Kombination der Systemdesignsoftware LabVIEW™ mit MATLAB [10].

Und kommen wir zu meinem Anfangsproblem zurück, dem Vermitteln von Programmierkenntnissen: Hier hat sich die Umstellung auf MATLAB wirklich als Segen erwiesen. Das Arbeiten mit MATLAB ist um einiges effektiver und führt schneller zu Ergebnissen. Alle wichtigen Programmiertechniken können wir auch mit Hilfe von MATLAB vermitteln, und dies sogar weitgehend schmerzlos, da man durch die einfache Nutzung der Grafikmöglichkeiten die Übungen viel anschaulicher gestalten kann.

Als kurze Einführung in die Welt von OOP mit MATLAB soll dies hier genügen. Weitergehende Informationen zu diesem Thema finden Sie in der MATLAB-Online-Hilfe [3], in meinem OOP-Buch [7] und auch auf meiner Internet-Seite [8].

Quellen
  1. Kernighan, B., Ritchie, D.: The C Programming Language. Verlag Prentice-Hall 1988
  2. Mathworks-Homepage
  3. MATLAB-Hilfe 
  4. Stein, U.: Programmieren mit MATLAB. Fachbuchverlag Leipzig/Hanser 2015
  5. Stroustrup, B.: Einführung in die Programmierung mit C++. Pearson Studium 2010
  6. Krüger, G. et al.: Java-Programmierung. O'Reilly 2014
  7. Stein, U.: Objektorientierte Programmierung mit MATLAB. Fachbuchverlag Leipzig/Hanser 2015
  8. Homepage Stein, U.: www.stein-ulrich.de/MATLAB/
  9. COMSOL und MATLAB
  10. LabVIEW und MATLAB

Autor

Prof. Dr. Ulrich Stein

Dr. Ulrich Stein ist Professor für Maschinenbauinformatik / Physik / Mathematik im Heinrich Blasius- Institut am Department Maschinenbau und Produktion der HAW Hamburg.
>> Weiterlesen
Bücher des Autors:

botMessage_toctoc_comments_9210