Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Beiträge: 1 223

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

11

03.08.2013, 00:14

Zitat

Oder wie wenn ich von einer Zahl z.B. den Cosinus berechnen lassen will.

Aus rein objektorientierter Sicht, müsste der Kosinus eine Memberfunktion sein und keine statische Funktion irgendwo Anders.

Zitat

transponierte Matrix eine Eigenschaft einer Matrix ist.

Ich würde sagen nein. Aber das ist sicherlich Ansichtssache.

Zitat

Also in C# gibt's auch "Templates" aber da heißen sie "Generics"

Das ist eine so abgespeckte Version, dass man das eigentlich nicht gleichstellen kann.
C++ Templates bieten wesentlich mehr Funktionalität als die Generics in C#
Zb. integrale Templateparameter, Spezialisierung oder SFINAE

Zitat

Würdet ihr die Matrix-Klasse im Namensbereich Math, Math.Matrix oder Math.Matrices definieren?

Im Namespace Math.
Die anderen Namen sind bloß redundant.

Um noch zu sagen, wie ich es in C++ gemacht habe:
Ich habe eine Template-Klasse mit M und N und der Type T als Templateparameter.
Ein Vorteil gegenüber deiner C#-Implementerung davon, ist das Überprüfen der Dimensionen zur Compilezeit.
Das "Problem der speziellen Matrixen" gibt es dank Templatespezialisierungen und std::enable_if dann gar nicht erst.
Zum transponieren habe ich zwei Funktionen. Die eine heißt "TransposeCopy"(Bei dir Variante 2) und die andere "Transpose"(Variante 3). Je nach Anwenungsfall können Beide nützlich sein.

In C# könnte ich mir als Lösung für Spezialfunktionen Vererbung schon vorstellen.

EDIT:
@h5::
Aber wieso man da nicht einfach einen Memberfunktion machen kann, verstehe ich nicht.
Das ist eigentlich von der Bedeutung für den Maschinencode exakt das Selbe, aber doch eigentlich schöner verpackt.
(Schon für kontextbezogene Syntaxvervollständigung)

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »Spiele Programmierer« (03.08.2013, 00:37)


H5::

Treue Seele

Beiträge: 368

Wohnort: Kiel

  • Private Nachricht senden

12

03.08.2013, 00:33

Aus rein objektorientierter Sicht, müsste der Kosinus eine Memberfunktion sein und keine statische Funktion irgendwo Anders.
Das sehe ich nicht so, im Gegenteil. Aber da scheiden sich eh die Geister. Ich bin nur der Meinung ein Auto kann blinken, ich kann ein Auto aber nicht Blinken sondern nur blinken lassen … bzw. Fahren. Der Sinus einer Zahl ist eine Zahl und keine Eigenschaft einer Zahl. Der Sinus selbst ist aber eine Bedeutung und als Bedeutung somit eigenständig. Aber ich bitte zu entschuldigen wenn meine Beispiele nicht sonderlich toll sind, mir ist zum Denken zu warm ;)

Edit: Wegen der Namensräume, warum nicht

Quellcode

1
Typ::Matrix
und evtl. im Gegensatz zu meinem Beispiel

Quellcode

1
Math::Matrix::Transpose
. Muss man nur mit einer eventuellen Namenskollision aufpassen, aber wenn man so ein Konzept strikt umsetzt funktioniert es aussagekräftig.
:love: := Go;

13

03.08.2013, 01:02

Okay, also ich fang' mal wieder bei H5:: an ;) :

Ist schon ok, bin in C++ zwar schon ein bisschen eingerostet (muss mal mein Avatar ändern :P ) aber jetzt versteh' ich (glaub ich) wie du's meintest: Jede Matrix mit unterschiedlichen Dimensionen ist ein anderer Typ (bitte korrigieren, wenn ich falsch liege) ? Nein, also jede Matrix ist vom Typ her gleich und unterscheidet sich nur durch das gekapselte 2D-Array. Das hat dann halt verschiedene Ausmaße. Aber die werden gleich beim Konstruktoraufruf als ganz normale Parameter übergeben. Aber deinen 2. Quelltext verstehe ich noch nicht ganz. Ich muss zugeben, sowas hab' ich noch nie gesehen ^^ ... Eigentlich vor allem der Teil hier:

C-/C++-Quelltext

1
2
template<unsigned m, unsigned n> auto Transpose( const Type::Matrix<m, n>& matrix)
    -> Type::Matrix<n, m>


@SpieleProgrammierer: Von was sollte der Kosinus eine Memberfunktion sein? Quasi vom Datentypen oder von einer speziellen Klasse? Bei C# ist ja der Kosinus als statische Methode der Math-Klasse definiert, mit einer double-Variable als Parameter und Rückgabewert... Wenn ich dich richtig verstehe, sollte der Kosinus so abrufbare sein ?:

C#-Quelltext

1
2
3
4
5
...
   Int32 var1 = 11;

   var var2 = var1.Cos(); // Kosinus ist eine Memberfunktion des int Datentyps
...


Ich finde aber nicht (Achtung! Nur meine Meinung ;) ), dass der Kosinus direkt eine Eigenschaft einer Zahl ist... Von daher würde ich die Berechnung nicht einer Memberfunktion des Werttypen überlassen, sondern in eine extra Klasse verlagern... Ok ja, ich hab' die Templates in C++ eig. immer nur zur Realisierung variabler Typen benutzt. Das können ja beide. Ansonsten hast du Recht. Da bietet C++ einiges mehr an Möglichkeiten.

Momentan bin ich aber ziemlich auf Möglichkeit 2 wieder fixiert: Memberfunktion mit Matrix-Rückgabewert und evtl. einer Memberfunktion, ohne Rückgabewert, die die Matrix direkt verändert... Aber mal so: Ein List<T>-Objekt wird ja beim Aufruf von "Reverse()" auch direkt verändert (Möglichkeit 3) . Gibt es im .NET-Framework auch Klassen, die das mit meiner Möglichkeit 2 regeln? Ich meine funktionierender Code ist zwar gut (würden ja auch alle Möglichkeiten), aber wenn man dabei noch den "Richtlinien" einigermaßen treu bleibt, wäre es natürlich optimal...

@H5:: : Ist "Typ::Matrix" bei dir der Namensraum, oder Matrix schon die Klasse :) ?

Beiträge: 1 223

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

14

03.08.2013, 01:31

Zitat

Ich finde aber nicht (Achtung! Nur meine Meinung ), dass der Kosinus direkt eine Eigenschaft einer Zahl ist...

Das finde ich auch nicht.
Aber ich finde das es eine Funktion ist die Zahlen anbieten.
Wenn es nicht ausgerechnet ein integraler Typ wäre von dem man das von jeher so akzeptiert hat, würde sich auch fast niemand die Frage stellen und das so als Funktion erstellen. Bei "normalen Operatoren" ist es genauso.

H5::

Treue Seele

Beiträge: 368

Wohnort: Kiel

  • Private Nachricht senden

15

03.08.2013, 03:33

EDIT:
@h5::
Aber wieso man da nicht einfach einen Memberfunktion machen kann, verstehe ich nicht.
Das ist eigentlich von der Bedeutung für den Maschinencode exakt das Selbe, aber doch eigentlich schöner verpackt.
(Schon für kontextbezogene Syntaxvervollständigung)
Gleich vor weg, dies soll keine Belehrung sein. Jeder soll so Programmieren wie er es mochte oder wie seine Vorgaben sind. Ich spreche hier nur für mich.

Ich habe nie gesagt, dass man es nicht machen kann, nur ich finde nicht, dass man auch alles machen muss was möglich ist. Ich bin der Meinung, dass es wichtig ist sich so gut wie möglich an Paradigmen zu halten ( in dem Fall dem der Objektorientierung ) insbesondere bei so freien Sprachen wie C++. Man kann sie wie Standards betrachten, und erst Standards ermöglichen eine wirklich gute Zusammenarbeit.

Ich möchte nicht kleinkariert erscheinen, aber eventuell überlegst du sogar einmal einen Satz von dir: “Aber ich finde das es eine Funktion ist die Zahlen anbieten.” und diesen im Bezug darauf, dass es bei Objekten (hier der Zahl) nicht mehr Funktion sondern ausdrücklich Methode genannt wird. Auch das ein Operator ein Operator ist und keine Methode (Auch wenn Technisch wenig Unterschied besteht) sollte man nicht ignorieren.

Etwas was ich nicht verstehe sind die Fragen nach, ist der Funktionsaufruf so schneller, oder dieser. Dabei ist das Schwierigere und doch weit Effektivere eigentlich eine Algorithmenoptimierung. Code würde ich in den meisten Fällen erst am Ende einer Optimierung unterziehen. Damit will ich nicht sagen, dass man nicht auf seinen Code achten soll, aber sinnvoll und nicht so fixiert.

-> bennichamp
Eigentlich ist es nur eine Templatefunktion vom Typ m,n wie die Matrix auch. und sie gibt eine Matrix vom Typ n,m zurück. Ohne jetzt ins Detail zu gehen, übergibt man dieser Funktion eine Matrix vom Typ m,n so weiß C++ welche Funktion heran zu ziehen ist ( template function type deduction) daraus folgt der Rückgabetyp, sprich Matrix n,m. Verwirren darfst du dich nicht von dem ->, dies ist eine recht neue Schreibweise (trailing return), die ich recht gerne mag.

Zu den Namensräumen ( Muss man abwägen wie umfangreich alles wird, und ob es sich lohnt so weit zu strukturieren ):

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
namespace Type
{
    class Matrix;
    class Quaternion;
    class TypeXYZ;
}
namespace Math
{
    namespace Matrix
    {
        template<unsigned m, unsigned n>
        auto Transpose( const Type::Matrix<m, n>& matrix) -> Type::Matrix<n, m>;
        // Funktionen 
    }
    namespace Quaternion
    {
        // Funktionen
    }
    ...
}


Wikipedia: C++11 Alternative function syntax
Deducing template arguments from a function call expression
:love: := Go;

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »H5::« (03.08.2013, 03:38)


dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

16

03.08.2013, 10:09

Imo sollte man sich erstmal überlegen, ob es nicht besser wäre, wenn die Matrix ein struct wäre, anstatt einer Klasse... ;)

17

03.08.2013, 11:13

Moin Leute :) ...

@Spiele Programmierer: Also du wärst dafür, dass int-Variablen eine Memberfunktion besitzen sollten, die den Kosinus zurück liefert? Ich finde den Ansatz, je länger ich darüber Nachdenke, auch irgendwie recht interessant... Aber in der Mathematik ist es ja auch nicht so, das der Kosinus quasi ein Operator für eine Zahl ist. Man spricht ja auch von der Kosinus-Funktion. Von daher finde ich den Ansatz, hier eine externe Methode statt einer Memberfunktion zu benutzen auch eher logisch. Zumal man in C# ja durchaus die Möglichkeit gehabt hätte, den standard Werttypen auch Memberfunktionen mitzugeben (die sind da ja auch "ganz normale" Strukturen). Aber anscheinend hat sich MS ja dagegen entschieden und ich denke mal unter anderem auch aus o.g. Grund. Eine Matrix zu transponieren, ist aber dann m.M.n auch schon wieder durch einen Operator definiert.

@H5:: : Danke :) ! Ja, mit dem ganzen C++11 hab' ich mich ehrlich gesagt noch gar nicht beschäftigt... Aber man lernt ja Gott sei dank nie aus 8) .

@dot: Die Überlegung hab' ich durchaus schon gehabt, ich habe mich aber bewusst dagegen entschieden, weil:
  • Eine Matrix ist imo kein einfacher Werttyp mehr (so wie er in C# definiert ist (jede struct-Definition erbt implizit von der System.ValueType-Klasse)), sondern ein Komplexer Datentyp, der mehrere Wertetypen, auf "besondere" Art und Weise kapselt
  • Das MSDN empfiehlt für Objekte, die viele Operatoren, Memberfunktionen, etc. bereitstellen, sowieso Klassen zu verwenden. Da eine Matrix das tut, würde ich hier auch von den Strukturen weg tendieren.
  • Strukturen können in C# nicht beerbt werden. Wenn ich später dann speziellere Matrix-Klassen erstellen will (oder auch eine Vektor-Klasse, die ja eig. auch Matrizen sind), so könnte ich die Matrix nicht als Basisklasse verwenden
Hoffe es ist einigermaßen verständlich ;) ...

Beiträge: 1 223

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

18

03.08.2013, 12:54

Zitat

und diesen im Bezug darauf, dass es bei Objekten (hier der Zahl) nicht mehr Funktion sondern ausdrücklich Methode genannt wird. Auch das ein Operator ein Operator ist und keine Methode (Auch wenn Technisch wenig Unterschied besteht) sollte man nicht ignorieren.

Ich verstehe nicht, wieso man da einen Unterschied machen sollte. Wie du schon sagtest, sollte man Paradigmen möglichst treu bleiben. Also auch dem objektorientierten Paradigma. Nach dem Gesetz der Einfachheit sollten jegliche Art der Funktionen/Methoden oder wie auch immer du es nennen magst, gleich behandelt werden. Die Unterscheidung zwischen diesen, ist im Prinzip nur syntactic sugar.

Zitat

Also du wärst dafür, dass int-Variablen eine Memberfunktion besitzen sollten, die den Kosinus zurück liefert?

Ja.
Der nächste objektorientierte Schluss wäre, dass die Klassen "int" und Konsorten von der Klasse der Ganzzahltypen ableitet. Diese wiederum von den Festkommazahlen und diese wieder von den Zahlen im Allgemeinen. Das lässt sich in so fern begründen, als das eine "ist ein" Beziehung vorliegt. Trigonometrische Funktionen wie Sinus und Kosinus müssten dann als Member in der Klasse der allgemeinen Zahlen stecken. Eine sinnvolle Umsetzung dieser Beziehungen stelle ich mir sehr schwer vor und in C# unmöglich, wegen der fehlenden Struct-Vererbung, die du ja auch schon angesprochen hast.

Zitat

Aber in der Mathematik ist es ja auch nicht so, das der Kosinus quasi ein Operator für eine Zahl ist.

Die Mathematik wurde auch nicht nach den Prinzipien der Objektorientierung entworfen.

Zitat

Eine Matrix ist imo kein einfacher Werttyp mehr (so wie er in C# definiert ist (jede struct-Definition erbt implizit von der System.ValueType-Klasse)), sondern ein Komplexer Datentyp, der mehrere Wertetypen, auf "besondere" Art und Weise kapselt

Jeder Typ kapselt mehrere Typen.
Nach der Definition dürfte auch ein Vektor kein Wertetyp mehr sein.

Du solltest dir auf jedenfall auch der Nachteile bewusst sein.
Sehr häufig wirst du die Matrix explizit kopieren müssen, damit keine Seiteneffekte auftreten. Das kann man schnell mal vergessen und ein "const" gibt es in C# auch nicht, mit dem man das zur Compilezeit sicherstellen könnte.

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Spiele Programmierer« (03.08.2013, 13:32)


H5::

Treue Seele

Beiträge: 368

Wohnort: Kiel

  • Private Nachricht senden

19

03.08.2013, 13:50

Ich verstehe nicht, wieso man da einen Unterschied machen sollte. Wie du schon sagtest, sollte man Paradigmen möglichst treu bleiben. Also auch dem objektorientierten Paradigma. Nach dem Gesetzt der Einfachheit sollten jegliche Art der Funktionen/Methoden oder wie auch immer du es nennen magst, gleich behandelt werden. Die Unterscheidung zwischen diesen, ist im Prinzip nur syntactic sugar.
Einen Unterschied macht die Semantik. Man kann sich an diese halten, muss es aber nicht. Sie ist quasi das impliziete "bitte nicht betreten Schild" an einer Blumenwiese. Wohingegen die technischen Möglichkeiten eher eine Mauer darstellen... aber dafür gibts ja am Ende auch noch Panzer.

Ehrlich gesagt liegt meine Aussagen auch eher im ästhetischen Empfinden als einer Diskussion im Richtig oder Falsch.

Aber einmal ein Beispiel ( nicht vollständig! ) warum ich es wichtig finde Bedeutungen auch einzuhalten.

C-/C++-Quelltext

1
2
3
4
5
6
7
/// <summary>++ Generiert einen neuen bloeden Kommentar</summary>
Integer& Integer::operator++() 
{
    std::cout << "Haha Ueberraschung :P" << std::endl;
    
    return *this;
};
:love: := Go;

Werbeanzeige