Hallo,
ich schreibe meine Programme auf dem AVR (hauptsächliche mega328P,
mega644 und tiny841) hauptsächlich in avr-gcc.
Nun stellt sich mir die Frage, macht C++ inzwischen mehr Sinn als vor
ein paar Jahren? Ein Punkt, der mich in C etwas stört ist, dass man
keine Funktionen überlagern kann.
Die meisten Funktionen bestehen aus einer großen Kombination an kleinen
Funktionen. Um auch noch lesbar etwas zu schaffen, werden diese dann
unnötig lang.
Hermann U schrieb:> hauptsächliche mega328P,> mega644 und tiny841
Schau dir doch nur mal an was mit Arduino möglich ist und was nicht.
So, jetzt werden hier gleich sehr viele Leute sehr böse... Ich mag es
auch absolut nicht und bin absolut froh wenn alles sauber in C
geschrieben ist. Dennoch funktionieren tut es.
-D
Wenn du auf die C++-Features verzichtest, die nicht ordentlich
funktionieren (oder die massiv Code erzeugen), warum nicht? Ein paar
Klassen, überlagerte Funktionen und so weiter kannst du problemlos
nutzen.
Wieder die gleiche alte Diskussion. Das bisherige Fazit war immer: C++
kann durchaus Sinn machen da es an manchen Stellen gegenüber C
erhebliche Vereinfachungen bietet. Es ist einfach eleganter zu benutzen.
Man muss und sollte allerdings nicht den ganzen Funktionsumfang von C++
auf keinen Mikrocontrollern ausschöpfen.
Da ich Arduino Jünger bin darf ich die Features aufregungslos genießen.
Aber wenn man sich solche Brocken, wie den Linux Kernel anschaut, dann
ist recht klar, dass es auch ohne das ++ geht.
Ich verwende auch immer c++ wenn ich AVRs Programmiere, auch wenn ich
nicht mit Objekten rumhantiere.
Alleine wegen Namespace und enum struct.
Wenn man nur Features benutzt die der Compiler auflöst und kein Overhead
zur Laufzeit verursacht spricht nichts gegen c++.
Bei Verwendung von Klassen bin ich immer sparsam, man sollte Kosten und
Nutzen immer abwägen. Sobald wegen virtuellen Methoden eine Lookuptabele
angelegt werden muss, wird dadurch der Programmcode größer und man hat
Nachteile im Laufzeitverhalten.
nicht“Gast“ schrieb:> Warte nur, bis Moby hier aufschlägt. Der weiß wirklich Bescheid, was man> so alles auf einen Atmel braucht. ;)
Dann werde ich sofort von Jörg W.'s Angebot Gebrauch machen, ihn
rausbekamen zu lassen.
>Nun stellt sich mir die Frage, macht C++ inzwischen mehr Sinn als vor>ein paar Jahren? Ein Punkt, der mich in C etwas stört ist, dass man>keine Funktionen überlagern kann.
Eigenartig. Ein Feature, das ich praktisch nie verwende.
Außer in Verbindung mit schematisierten Klassen, die in vielen Fällen
den Code nur aufblähen, bringt das doch nichts - also was soll das?
Wenn ich Pferde und Äpfel addieren will, gibt es unter c++ die
Möglichkeit eine Funktion mit Namen Addiere_Etwas ( ... ) zu
implementieren.
In normalem c müsste ich dann Addiere_Pferde (...) und Addiere_Aepfel
(...) schreiben.
Und nur kommt der alles umwerfende Effekt:
"Unten" gibt es weiterhin zwei Funktionen die implementiert und gewartet
werden müssen.
Also bleibt als Erleichterung ein geringerer Bedarf an Fantasie bei der
Namensfindung.
Bei der Fehlerfindung allerdings wird etwas mehr Kreativität gefordert.
Der Effekt: Manchmal geht’s manchmal nicht wird dadurch verschmiert,
dass man bei gleichnamigen Aufrufen verschiedene Adressaten hat.
Das überladen von Funktionen ist auch ein sehr nützliches Features was
ich gerne verwende. Wenn man Funktionen hat die das gleiche machen, aber
mit unterschiedlichen Parametertüpen aufrufen möchte.
Z. B.:
@amateur:
Das ist genau die Mischung aus Vorurteilen und Unwissenheit, die zeigen,
daß da jemand schreibt, der das nich nie ausprobiert hat. Dies wird
nämlich in allen Punkte der Mangel der in C++ behoben wurde, diesem
angelastet.
Eine überladene Methode sorgt nämlich genau dafür, daß keine Äpfel auf
Pferde addiert werden. Nennt sich Typsicherheit.
Und wenn ich PferdeAddieren() und ÄpfelAddieren() brauche, dann gibt es
die ja auch beide.
Und daß ein Debugger die verschiedenen Aufrufsignaturen auseinander
halten kann, ist auch gewährleistet. Nennt sich "Name Mangling".
Carl D. schrieb:> Eine überladene Methode sorgt nämlich genau dafür, daß keine Äpfel auf> Pferde addiert werden. Nennt sich Typsicherheit.
Das hat er nicht behauptet, es ging um Pferde mit Pferden und Äpfel mit
Äpfeln zu addieren, aber eben mit nur einer Funktion.
So richtig gute Argumente für C++ hab ich hier noch nicht gehört.
Hat jemand ein gutes praktisches Beispiel, dass die Vorzüge von C++ auf
dem uC verdeutlicht?
Julian B. schrieb:> Hat jemand ein gutes praktisches Beispiel, dass die Vorzüge von C++ auf> dem uC verdeutlicht?
... nicht nur auf µC, sondern generell:
hate this schrieb:> Datenkapselung und einen typesicheren enum
Eine einfache GUI ist der Musterkandidat für Objektorientierung. Das
kann man alles auch in C machen, aber es lässt sich in C++ einfach
schöner umsetzen.
Oder eine allgemeine Ringbuffer-Implementation: In C braucht man eine
Implementation pro Datentyp, oder man arbeitet immer auf void* und muss
dann eine Speicherverwaltung haben. Wenn man es nicht übertreibt (d.h.
den Code aufbläht), dann ist das in C++ mit weniger hingeschriebenem
Code machbar.
Christian K. schrieb:> Sobald wegen virtuellen Methoden eine Lookuptabele> angelegt werden muss, wird dadurch der Programmcode größer und man hat> Nachteile im Laufzeitverhalten.
Wenn man Polymorphismus und virtuelle Methoden aber braucht, weil die
Anwendung das erfordert, ist eine handgehäkelte Version in reinem C sehr
wahrscheinlich nicht viel besser als das, was ein C++-Compiler macht.
Letzterer ist bei sowas aber deutlich sorgfältiger als die meisten
Programmierer ;)
Das schöne an C++ ist, dass man auch in "C mit Klassen" programmieren
kann. Ich benutze unter anderem auch C++ auf kleinen Mikrocontrollern,
vor allem folgene Dinge empfinde auf einem uC ich als Vorteile gegenüber
C:
- Konstruktoren/Destruktoren
- namespaces
- Typensichere enums
- Templates
- Überladung von Funktionen/Operatoren
- Vererbung
- Iteratoren
structs habe ich fast komplett durch Klassen ersetzt, was auch die Länge
der Funktionsnamen verkürzt und die Datenkapselung begünstigt.
Statt
1
DisplayWrite(Display,String);
schreibe ich nun
1
Display.Write(String);
was meiner Meinung nach angenehmer und übersichtlicher ist.
Hardwarenahe Dinge sind nahezu idetisch wie in C und lassen sich in C++
genau so gut kapseln. Ist halt stupides Bitgeschubse.
Edit:
Fast vergessen, leider gibt es keine offizielle Standardbibliothek, was
sicher auch daran liegt, dass Exceptions auf kleinen uCs meist
unerwünscht sind. Deswegen, habe ich die Dinge, die ich benötige, selbst
programmiert/kopiert, damit ich bestehende Software nutzen kann.
Einfaches Beispiel ist die Definition von size_t und der (u)int_fastXX_t
Typen im std namespace.
Da ich beruflich in Java programmiere und mit C++ auch sehr gut vertraut
bin, würde ich meine AVR Projekte auch gerne in C++ schreiben.
Aber dabei bin ich einige male unerwartet an die Speicher-Grenzen
gestoßen. In C ist mir das noch nie passiert, deswegen bin ich wieder
auf C zurück gekommen.
Stefan U. schrieb:> Aber dabei bin ich einige male unerwartet an die Speicher-Grenzen> gestoßen. In C ist mir das noch nie passiert, deswegen bin ich wieder> auf C zurück gekommen.
Wie kann man unerwartet an Speichergrenzen stoßen die es in C nicht
gibt? Das einzige was mir dazu einfällt ist in C++ wie in Java zu
Programmieren (überall New und nicht ordentlich aufräumen) oder
unüberlegte Verwendung von STL Containern (die auch viel dynamische
Speicherverwaltung brauchen).
Std:array zum Beispiel hat keinen Laufzeit Overhead verglichen mit c
Arrays aber den ganzen STL Komfort. Einfache Klassen ermöglichen
ordentliche Kapselung und saubere Namensräume ohne Kosten. Statischer
Polymorhismus ermöglicht dann noch viele Vorteile von Vererbung ohne
virtuelle Funktionen. Templates und Templatemetaprogrammierung
ermöglichen eleganten und vom Compiler sehr gut optimierbaren Code zu
generieren, der in C zu ifdef Orgien ausartet. Insbesondere in
Kombination mit constexpr und Static_assert kann viel Code vom Compiler
erledigt und geprüft werden ohne jemals den uC Kern zu erreichen.
Das ganz einfache Problem mit C++ ist, dass es komplexer ist als das was
man als normaler Programmierer verstehen kann. Die wenigen Leute, die
C++ verstehen, arbeiten in aller Regel nicht als C++ Programmierer
sondern schreiben Bücher über C++, bzw arbeiten als "Sprach-Guru".
Eine Programmiersprache, welche ich nicht vollständig verstehen kann,
führt dazu, dass ich ggf. Fehler mache, die ich nicht vorhersehen kann.
Ein typisches Beispiel sind die vielen "Gleichheitsoperatoren" in
Sprachen wie PHP.
Christian B. schrieb:> Eine Programmiersprache, welche ich nicht vollständig verstehen kann,> führt dazu, dass ich ggf. Fehler mache, die ich nicht vorhersehen kann.
Dann hast du aber beim Erlernen jeglicher Sprache ein Problem. Denn jede
hat ihre Fallstricke und kann deshalb ja nicht benutzt werden, womit die
Chance flöten geht, sie zu lernen. Ein "Devil Circle"!
Christian B. schrieb:> Das ganz einfache Problem mit C++ ist, dass es komplexer ist als das was> man als normaler Programmierer verstehen kann.
Milliarden von LOC in C++ beweisen das Gegenteil.
> Eine Programmiersprache, welche ich nicht vollständig verstehen kann,> führt dazu, dass ich ggf. Fehler mache, die ich nicht vorhersehen kann.
Wenn Du C++ nicht verstehst, muß das nicht an C++ liegen. Was genau hast
Du denn daran nicht verstanden?
> Ein typisches Beispiel sind die vielen "Gleichheitsoperatoren" in> Sprachen wie PHP.
Nichts gegen ein ordentliches Bashing gegen PHP, aber es als "Argument"
gegen C++ zu benutzen, ist, vorsichtig gesagt, daneben.
Hermann U schrieb:> Hallo,>> ich schreibe meine Programme auf dem AVR (hauptsächliche mega328P,> mega644 und tiny841) hauptsächlich in avr-gcc.>> Nun stellt sich mir die Frage, macht C++ inzwischen mehr Sinn als vor> ein paar Jahren? Ein Punkt, der mich in C etwas stört ist, dass man> keine Funktionen überlagern kann.
Das ging mit g++ auf dem AVR aber schon immer. Warum war das deiner
Meinung nach denn "vor ein paar Jahren" nicht sinnvoll?
Carl D. schrieb:> Dann hast du aber beim Erlernen jeglicher Sprache ein Problem. Denn jede> hat ihre Fallstricke und kann deshalb ja nicht benutzt werden, womit die> Chance flöten geht, sie zu lernen. Ein "Devil Circle"!
Naja, eine "normale" Sprache wird in einem Lehrbuch mit vielleicht
100-200 Seiten komplett beschrieben, da kann man einen vernünftigen Teil
der Sprache begreifen. C++ (und seine Nachfahren) hingegen sind hoch
komplex mit immer neuen Funktionen die so halb das machen was schon
bestehende Funktionen gemacht haben.
Es gibt ja genügend Leute die sich kritisch mit C++ befasst haben...
besonders schön ist es, wenn C++ Gurus sich dazu äußern.
https://www.youtube.com/watch?v=48kP_Ssg2eY
C++ (uns seine Nachkommen) mag sinnvolle Anwendungen haben, die meisten
Probleme in der IT werden jedoch durch die Verwendung von C++-Features
eher komplexer als einfacher. Mehr Komplexität bedeutet mehr Fehler und
mehr Wartungsaufwand, deshalb sollte Komplexität meiner Ansicht nach
vermieden werden.
Es gibt ja auch in C++ nicht das "strahlende Beispiel" für ein so
richtig erfolgreiches Projekt. Bei C ist das zum Beispiel UNIX. Wenn
C++-Leute ein Betriebssystem programmieren... naja die Ergebnisse sehen
viele Leute ja täglich.
Christian B. schrieb:> eine "normale" Sprache
Mit deinem Text, bin ich nun gar nicht einverstanden....
C/C++ ist eine normale Sprache
ca 40 Jahre alt, läuft auf dem kleinsten AVR und auf den, ganze Keller
füllenden, Mainframes.
Man könnte sagen, dass die OOP zu früh dran geklemmt wurde. Andere
Sprache verzichten z.B. auf Friends und Polymorphie.
Christian B. schrieb:> mit immer neuen Funktionen
Du meinst die Bibliotheken?
Das werden immer mehr. Ganz normales Wachstum. Das ist bei C# nix
anders.
Christian B. schrieb:> Wenn> C++-Leute ein Betriebssystem programmieren... naja die Ergebnisse sehen> viele Leute ja täglich.
Verstehe ich nicht...
Kenne kein in C++ geschriebenes Betriebssystem....
Christian B. schrieb:> Es gibt ja auch in C++ nicht das "strahlende Beispiel" für ein so> richtig erfolgreiches Projekt.
Unmengen an Desktopanwendungen beweisen das Gegenteil. Nur weil da nicht
in jedem Dialog Fensterchen C++ steht, sind sie nicht in C++
geschrieben?
Ulrich F. schrieb:> Christian B. schrieb:>> eine "normale" Sprache> Mit deinem Text, bin ich nun gar nicht einverstanden....>> C/C++ ist eine normale Sprache
"C/C++" ist gar keine Sprache. Es gibt die Sprache C und die Sprache
C++.
> ca 40 Jahre alt, läuft auf dem kleinsten AVR und auf den, ganze Keller> füllenden, Mainframes.> Mann könnte sagen, dass die OOP zu früh dran geklemmt wurde. Andere> Sprache verzichten z.B. auf Friends und Polymorphie.
Polymorphie ist so ziemlich das grundlegendste Element der
objektorientierten Programmierung.
> Christian B. schrieb:>> mit immer neuen Funktionen> Du meinst die Bibliotheken?
Schau dir mal C++11 im Vergleich zu C++98 an. Da gibt es neben den
erweiterten Bibliotheken auch enorm viele neue Funktionalitäten im
Sprachkern selbst.
Siehe
https://en.wikipedia.org/wiki/C++11#Extensions_to_the_C.2B.2B_core_language
Viele davon halte ich durchaus für sinnvoll, aber da man zu alten
Versionen kompatibel sein will und dehsalb veraltete Konstrukte nicht
wegwirft, wird die Sprache dadurch auch enorm umfangreich und komplex.
> Christian B. schrieb:>> Wenn>> C++-Leute ein Betriebssystem programmieren... naja die Ergebnisse sehen>> viele Leute ja täglich.> Verstehe ich nicht...> Kenne kein in C++ geschriebenes Betriebssystem....
Naja, die Frage ist, wie man "Betriebssystem" definiert. Bezieht sich
das auf den Kernel, die Treiber, die Oberfläche, die Systemtools, ...?
Oder alles zusammen?
Ich nutze Kubuntu, und das darin verwendete KDE ist nahezu komplett in
C++ geschrieben.
Rolf M. schrieb:> Polymorphie ist so ziemlich das grundlegendste Element der> objektorientierten Programmierung.
Vielleicht habe ich das falsche Wort verwendet...
Mehrfachvererbung war gemeint.
Rolf M. schrieb:> Funktionalitäten
Er/Sie/Es sprach von Funktionen!
Rolf M. schrieb:> Ich nutze Kubuntu, und das darin verwendete KDE ist nahezu komplett in> C++ geschrieben.
Sach ich ja...
Desktop.
Ist bei Windoofs nicht viel anders.
Christian B. schrieb:> C++ (uns seine Nachkommen) mag sinnvolle Anwendungen haben, die meisten> Probleme in der IT werden jedoch durch die Verwendung von C++-Features> eher komplexer als einfacher.
Ähm. Wenn ein Programm durch die Verwendung bestimmter Sprachmittel
komplexer wird als ohne, dann liegt der Fehler nicht in der
Programmiersprache, sondern ausschließlich beim Programmierer.
Gerade im Fall von C++ ist das überhaupt kein Argument, denn schließlich
ist jedes [1] C-Programm ein gültiges C++ Programm. Man kann also in C++
exakt genauso "unkomplex" programmieren wie in C. Das übrigens im
krassen Gegensatz zu Java, das den Programmierer zwingt, alles in sein
Objektschema zu pressen. Auch dann wenn es ganz offensichtlich unsinnig
ist [2].
Wenn irgendein Sprachfeature von C++ das Programm also komplexer
(unübersichtlicher, weniger lesbar) machen würde, dann muß sich der
Programmierer fragen lassen, warum er es denn überhaupt verwendet.
Allerdings zeigt die Praxis eher das Gegenteil. Die meisten C-Programme
lassen sich durch den Gebrauch von C++ Features kürzer und lesbarer
hinschreiben.
[1] offensichtliche Ausnahme: neue Schlüsselworte in C++. Die darf man
in einem C-Programm natürlich nicht als Bezeichner verwenden, wenn man
es mit dem C++ Compiler übersetzen will.
[2] klassisches Beispiel: main(). Ein Programm hat genau eine main()
Funktion. Aber weil Java keine alleinstehenden Funktionen erlaubt, muß
man eine Dummy-Klasse mit einer statischen main() Methode verwenden.
Bescheuert³
Ulrich F. schrieb:> Rolf M. schrieb:>> Polymorphie ist so ziemlich das grundlegendste Element der>> objektorientierten Programmierung.> Vielleicht habe ich das falsche Wort verwendet...> Mehrfachvererbung war gemeint.
Ach so. Andere Sprachen wie Java haben so was ähnliches auch, nur ist es
halt eingeschränkt und heißt anders.
> Rolf M. schrieb:>> Funktionalitäten> Er/Sie/Es sprach von Funktionen!
Ich vermute, dass das nicht im Sinne von C-Funktionen, sondern allgemein
im Sinne von Funktionalitäten gemeint ist.
> Rolf M. schrieb:>> Ich nutze Kubuntu, und das darin verwendete KDE ist nahezu komplett in>> C++ geschrieben.> Sach ich ja...> Desktop.>> Ist bei Windoofs nicht viel anders.
Dann ist aber die pauschale Aussage, es sei nicht in C++ geschrieben,
falsch.
Rolf M. schrieb:> Dann ist aber die pauschale Aussage, es sei nicht in C++ geschrieben,> falsch.
Vorsicht mit den Äpfeln und den Birnen...
;-)
Christian B. schrieb:> Bei C ist das zum Beispiel UNIX.
Ich denke Christian meint den Unix Kern. Der ist in C geschrieben. Man
könnte sogar sagen, dafür wurde C erfunden.
Der Windows Kern ist ebenso in C geschrieben, soweit mir bekannt.
Rolf M. schrieb:> und heißt anders.
Interfaces !?!?
Mir persönlich gefällt das VIEL besser
(aber was mir gefällt ist ja hier nicht gefragt worden)
Rolf M. schrieb:> "C/C++" ist gar keine Sprache. Es gibt die Sprache C und die Sprache> C++.
Liegt ein bisschen daran, ob man die Unterschiede betonen möchte, oder
die Gemeinsamkeiten.
Zu Zeiten meiner ersten C Kontakte war C nicht viel mehr als ein
erweiterter Macro Assembler. Und später wurden dann ersten die OOP
Erweiterungen als Präprozessor Statements dran geklebt.
Lang ist es her....
Axel S. schrieb:> Wenn irgendein Sprachfeature von C++ das Programm also komplexer> (unübersichtlicher, weniger lesbar) machen würde, dann muß sich der> Programmierer fragen lassen, warum er es denn überhaupt verwendet.
Zumindest wird es immer in dem Sinn komplexer, dass man diese Features
auch alle kennen muss, um das Programm zu verstehen. Die Anwendung der
Sprache generell wird also komplexer. Wenn das Programm selbst dadurch
komplexer wird, gebe ich dir recht. Dann ist was schief gelaufen.
> [1] offensichtliche Ausnahme: neue Schlüsselworte in C++. Die darf man> in einem C-Programm natürlich nicht als Bezeichner verwenden, wenn man> es mit dem C++ Compiler übersetzen will.
Das ist nicht die einzige Ausnahme. C hat sich unabhängig von C++
weiterentwickelt, und so gibt es auch C-Features, die C++ so nicht hat,
z.B. VLAs.
> [2] klassisches Beispiel: main(). Ein Programm hat genau eine main()> Funktion. Aber weil Java keine alleinstehenden Funktionen erlaubt, muß> man eine Dummy-Klasse mit einer statischen main() Methode verwenden.> Bescheuert³
Nicht nur main(). Teils gibt es auch Hilfsfunktionen, die eigentlich
freistehend sein sollten. In Java muss man die auch irgendwie in
Dummy-Klassen zusammenfassen. Eine Klasse, die niemals instanziiert wird
und von der auch nie geerbt wird, geht für mich irgendwie am Sinn von
Klassen vorbei.
> Rolf M. schrieb:>> und heißt anders.> Interfaces !?!?> Mir persönlich gefällt das VIEL besser> (aber was mir gefällt ist ja hier nicht gefragt worden)
Ich find's irgendwie blöd. In C++ nehme ich eine abstrakte Basisklasse
und kann damit das gleiche machen, nur daß die auch Code enthalten darf.
In Java darf ich nur von einer Klasse ableiten, die Code enthält. Alles
andere, von dem ich ableite (die Interfaces) müssen leer sein. Ich sehe
keinen besonderen Sinn in einer derartigen Einschränkung.
> Rolf M. schrieb:>> "C/C++" ist gar keine Sprache. Es gibt die Sprache C und die Sprache>> C++.> Liegt ein bisschen daran, ob man die Unterschiede betonen möchte, oder> die Gemeinsamkeiten.
Ich mag es eben nicht, dass die beiden so häufig in einen Topf gesteckt
und als eine einzelne Sprache bezeichnet werden. Spricht ja auch keiner
von "der Sprache C#/Java".
Ich habe es wieder aufgegeben bzw. musste mir wegen der Unzulänglichkeit
des gcc, vtables in das flash zu legen, eine ähnliche Struktur schaffen,
indem ich massiv Templates genutzt habe. Mein Fazit: templates & co sind
angenehm und machen vieles einfacher, virtuelle Klassen machen Probleme
durch vermehrten RAM-Verbrauch, weil der Compiler mit der Architektur
des AVR nicht gut umgehen kann. Ergo, ich nutze seit dem eher STM und
dann C++ oder nur noch bei kleineren Projekten AVR und eine geschrumpfte
Untermenge von C++. Dort nutze ich vor allem Dinge wie z.B. Templates
für Ringpuffer.
Christian K. schrieb:> Das überladen von Funktionen ist auch ein sehr nützliches Features was> ich gerne verwende. Wenn man Funktionen hat die das gleiche machen, aber> mit unterschiedlichen Parametertüpen aufrufen möchte.> Z. B.:
1
voidsend(constcharc){
2
>...
3
>}
4
>
5
>voidsend(constchar*s){
6
>while(*s){
7
>send(*s++);
8
>}
9
>}
Und wie sendest du einen String, der im Flash steht?
Axel S. schrieb:> klassisches Beispiel: main(). Ein Programm hat genau eine main()> Funktion. Aber weil Java keine alleinstehenden Funktionen erlaubt, muß> man eine Dummy-Klasse mit einer statischen main() Methode verwenden.> Bescheuert³
Und warum sollte man für genau diesen Einzelfall (gibt es pro Programm
genau einmal) eine eigene Syntax/Sprachfeature einbauen, wo es doch
genauso gut mit der bestehenden Funktionalität klappt? Das erhöht doch
nur sinnlos die Komplexität.
Rolf M. schrieb:> Nicht nur main(). Teils gibt es auch Hilfsfunktionen, die eigentlich> freistehend sein sollten. In Java muss man die auch irgendwie in> Dummy-Klassen zusammenfassen. Eine Klasse, die niemals instanziiert wird> und von der auch nie geerbt wird, geht für mich irgendwie am Sinn von> Klassen vorbei.
Es sollte so wenig wie möglich freistehend = global sein. Ist doch
absolut sinnvoll, Hilfsmethoden zu strukturieren und zu verpacken. Und
auch wenn die statisch sind, so sind sie durch die Klassen doch gut
gekapselt.
In der OO-Lehre steht meist die Vererbung im Vordergrund. Für mich
persönlich spielt die aber ganz und gar nicht die Hauptrolle bei der
OO-Programmierung. Man muss eben nicht alles in instanziierte und sieben
Mal abgeleitete und Interfaceüberladene Methoden stecken.
Jan H. schrieb:> Es sollte so wenig wie möglich freistehend = global sein. Ist doch> absolut sinnvoll, Hilfsmethoden zu strukturieren und zu verpacken. Und> auch wenn die statisch sind, so sind sie durch die Klassen doch gut> gekapselt.
(Dafür gibt es in C++ einen namespace.
Es spricht natürlich nichts prinzipielles dagegen, wenn man keinen
namespace hat, dafür ein Klasse zu nehmen und nichts reinzuschreiben,
wenn man es nicht braucht.)
Aber interfaces in Java sind in der Tat eine Einschränkung, weil man
denselben Code ggf. in mehreren Instanzen schreiben muß - nur damit der
Compiler einfacher gebaut werden kann.
Viele Java-Programmierer finden interfaces toll, und realisieren gar
nicht, daß es kastrierte Klassen sind.
Rolf M. schrieb:> Axel S. schrieb:>> Wenn irgendein Sprachfeature von C++ das Programm also komplexer>> (unübersichtlicher, weniger lesbar) machen würde, dann muß sich der>> Programmierer fragen lassen, warum er es denn überhaupt verwendet.>> Zumindest wird es immer in dem Sinn komplexer, dass man diese Features> auch alle kennen muss, um das Programm zu verstehen.
Unsinn. Hier ging es darum ob es sinnvoll ist, selber C++ zu
programmieren. Nicht darum, fremde C++ Programme zu verstehen.
Und wer in seinen eigenen Programmen Sprachfeatures verwendet die er
nicht versteht, der ist alles, aber kein Programmierer.
> Das ist nicht die einzige Ausnahme. C hat sich unabhängig von C++> weiterentwickelt, und so gibt es auch C-Features, die C++ so nicht hat,> z.B. VLAs.
Du beliebst zu scherzen. VLA sind im GCC schon seit Ewigkeiten als
Erweiterung drin. Und funktionieren selbstverständlich in C++ genauso
wie in C (ok, fast: gcc muß man explizit sagen daß er VLA akzeptieren
soll, für g++ ist das der Default):
cat test.c
1
#include<stdio.h>
2
3
voidmake_array(intn)
4
{
5
intthe_array[n];
6
for(inti=0;i<n;i++)
7
the_array[i]=i;
8
for(inti=0;i<n;i++)
9
printf("%d -> %d\n",i,the_array[i]);
10
}
11
12
intmain(void)
13
{
14
make_array(10);
15
return0;
16
}
1
/tmp $gcc -std=c99 test.c -o test_c
2
3
/tmp $g++ test.c -o test_c++
4
5
/tmp $ls -l test*
6
-rw-r--r-- 1 axel axel 233 Dec 19 13:49 test.c
7
-rwxr-xr-x 1 axel axel 7008 Dec 19 13:53 test_c*
8
-rwxr-xr-x 1 axel axel 7248 Dec 19 13:53 test_c++*
Axel S. schrieb:> Du beliebst zu scherzen. VLA sind im GCC schon seit Ewigkeiten als> Erweiterung drin.
Genau, als Erweiterung zum Standard. Ich verwende ungern
Compilererweiterungen, denn ich habe keine Lust, dass ein Programm mit
Compiler X kompiliert werden kann, mit Compiler Y aber zu Fehlern führt.
GCC ist nicht das Mass aller Dinge.
Klaus W. schrieb:> Aber interfaces in Java sind in der Tat eine Einschränkung, weil man> denselben Code ggf. in mehreren Instanzen schreiben muß - nur damit der> Compiler einfacher gebaut werden kann.>> Viele Java-Programmierer finden interfaces toll, und realisieren gar> nicht, daß es kastrierte Klassen sind.
Da habe ich Schmerzen mit....
In der Regel haben Sprachen ohne Mehrfachvererbung irgend ein Interface
Konzept.
Vielleicht auch manche beides, ka.
Mehrfachvererbung bringt auch so seine Probleme mit sich...
Es wurde in C++ eingebaut, aber ich glaube, dass sich die Entwickler
immer noch reihenweise dafür selber in den Arsch beißen. Jetzt kommen
sie nicht mehr weg davon, ohne dass Tonnen von Code unbrauchbar werden.
> Compiler einfacher gebaut> kastrierte Klassen
Ein sehr subjektiver Blickwinkel
Jan H. schrieb:> Axel S. schrieb:>> klassisches Beispiel: main(). Ein Programm hat genau eine main()>> Funktion. Aber weil Java keine alleinstehenden Funktionen erlaubt, muß>> man eine Dummy-Klasse mit einer statischen main() Methode verwenden.>> Bescheuert³>> Und warum sollte man für genau diesen Einzelfall (gibt es pro Programm> genau einmal) eine eigene Syntax/Sprachfeature einbauen, wo es doch> genauso gut mit der bestehenden Funktionalität klappt?
Die übliche Formulierung ist "Würgaround" oder "übler Hack".
Nicht "bestehende Funktionalität".
> Das erhöht doch nur sinnlos die Komplexität.
Ich finde es im Gegensatz unnötig komplex, eine Dummyklasse definieren
zu müssen, die als einzigen Member eine main() Methode hat.
Und selbstverständlich ist main() keineswegs ein Einzelfall. Man könnte
einen ganzen Thread damit füllen. Aber nur für dich noch ein paar:
min(), max(), sort()
Und um wieder zum Thema zurück zu kommen: natürlich will man min() und
max() als typsichere C++ Templates schreiben und nicht als C Makro.
> Es sollte so wenig wie möglich freistehend = global sein.
Sagt wer? Und wieso ist freistehend = global? Namespaces existieren.
> In der OO-Lehre steht meist die Vererbung im Vordergrund. Für mich> persönlich spielt die aber ganz und gar nicht die Hauptrolle bei der> OO-Programmierung. Man muss eben nicht alles in instanziierte und sieben> Mal abgeleitete und Interfaceüberladene Methoden stecken.
Ich würde mal sagen, daß OO viel zu oft als Allheilmittel angesehen
wird. Ist es aber nicht. Es gibt Dinge die man OO besser ausdrücken
kann. Und andere für die das nicht gilt. Eine gute Programmiersprache
sollte dem Rechnung tragen indem sie beide (bzw. überhaupt mehrere)
Paradigmen zur Wahl stellt. Das machen eigentlich alle modernen
Programmiersprachen. Und C++
be s. schrieb:> Axel S. schrieb:>> Du beliebst zu scherzen. VLA sind im GCC schon seit Ewigkeiten als>> Erweiterung drin.>> Genau, als Erweiterung zum Standard. Ich verwende ungern> Compilererweiterungen, denn ich habe keine Lust, dass ein Programm mit> Compiler X kompiliert werden kann, mit Compiler Y aber zu Fehlern führt.> GCC ist nicht das Mass aller Dinge.
Da stimme ich gröstenteils zu, aber eine Erweiterung ist es nur in C++,
nicht aber in C.
Axel S. schrieb:> Und funktionieren selbstverständlich in C++ genauso> wie in C (ok, fast: gcc muß man explizit sagen daß er VLA akzeptieren> soll, für g++ ist das der Default)
Ich finde, dass man dem GCC extra sagen muss er soll sich an den
Standard XY halten wirklich schlecht. Ich verstehe nicht warum Sie
momentan gnu++98 bzw. gnu99 statt c++98 und c99 als default setzen.
-----------------
Ich finde C++ eigentlich ganz gut, aber:
* Ich vermisse einige komfortable C Features, wie z.B. Variable Length
Arrays und designated initializers.
* Mir gefällt nicht, dass ich für gewisse Templates die Funktionen
inline im Header in der Klasse haben muss, und so Code und Interface
nichtmehr sauber trennen kann.
* Dass es statt Interfaces nur Abstrakte Klassen gibt, dies führt zu
Problemen wie dem Diamond-Problem. Besser wäre es gewesen, wenn Daten,
Funktionsinterfaces und Implementierungen getrennt hätte, aber nicht so
wie in "go", die generieren overhead.
* Zu viele Wege führen nach Rom. Soll ich nun eine "Disc<CD_ROM>"
(Template+enum), eine "class CDRom : Disc" (Vererbung) oder eine
"Disc(CD_ROM)" (Constructor+enum) erstellen? Egal, ich nehmen C++11 und
schreibe "1024_memory"! (User-defined literal)
* Es gibt keinen einfachen weg zu Prüfen, ob ein Feature unterstützt
wird, und jenachdem Compielerunabhängig mit eigenen Implementierungen zu
Ersetzen. Das gilt allerdings auch für C. Man stelle sich nur mal for,
man will std::thread verwenden, aber wenn es das nicht gibt ein Wrapper
schreiben mit POSIX Pthreads, aber auf der ARM Version immer einen
Wrapper auf irgendwelche Rtos funktionen verwenden. Was nun?
* Kompilerabhängige Dinge wie Name Mangling, für Libraries pures Gift,
und dann kann man Klassen nichteinmal in ein extern C setzen...
* Komplexität, Beispiel: lvalue, rvalue und rvalue referenzen, ich will
möglichst jeden Kopiervorgang und Redundanz verhindern. Eine Funktion
soll deshalb sowohl eine lvalue als auch eine rvalue als Argument nehmen
können; Verwende ich keine Referenz als Argumenttype, wird Kopiert.
Verwende ich eine, kann ich keine rvalue übergeben. Verwende ich eine
rvalue-referenz, kann ich keine lvalue mehr übergeben, und überlade ich
die Funktion, gibt es uneindeutige Situationen. Ein schönes Happy End
gibt es nicht, entweder man nutzt die Kopierveriante, oder die Referenz
variante und speichert rvalues in lvalues vor dem Aufruf...
Was ich noch Praktisch fände, und es noch in keiner Programmiersprache
gibt:
* Compile Time Reflection. Damit könnte man zur Compile Time Code zur
Serialisierung/Deserialisierung von Klassen, etc. erstellen. Ich glaube
dass wird gerade für C++1z/C++17 diskutiert, aber ich kann mir nicht
vorstellen, wie die dass auchnoch brauchbar in die Sprache hineinzwägen
wollen, ist mir schleierhaft.
* IO in Templates zur Compile Time
Ulrich F. schrieb:> Mehrfachvererbung bringt auch so seine Probleme mit sich...> Es wurde in C++ eingebaut, aber ich glaube, dass sich die Entwickler> immer noch reihenweise dafür selber in den Arsch beißen. Jetzt kommen> sie nicht mehr weg davon, ohne dass Tonnen von Code unbrauchbar werden.>
Wenn man meint nur Einfachvererbung und Interfaces zu brauchen, kann man
das in jedem C++ Projekt jederzeit so machen. Gibt ja abstrakte
Basisklassen als Interface.
Das ist der große Unterschied zwischen Sprachen wie Java und C++. Java
verbietet einfach viele "gefährliche" und übermäßig komplexen Sachen,
baut Laufzeitprüfungen und GCs ein, C++ erlaubt alles was der Compiler
dem Programmierer irgendwie ermöglichen kann. Das erstere hat sicher
viel Code besser gemacht, aber Grenzen in Performance oder Eleganz lotet
sicher kein Java Programm aus. Insbesondere die erbärmlichen
Implementierung von Geneerics in Java stimmt jeden traurig der die Macht
der C++ Templates kennengelernt hat. Andererseits sind die
Compilerfehler bei Templateproblemen immer noch was für
Hardcoreprogrammierer.;)
Scelumbro schrieb:> Wenn man meint nur Einfachvererbung und Interfaces zu brauchen, kann man> das in jedem C++ Projekt jederzeit so machen. Gibt ja abstrakte> Basisklassen als Interface.
Aber diese lösen dass Diamond-Problem nicht, oder?
https://de.wikipedia.org/wiki/Diamond-Problem
Daniel A. schrieb:> Scelumbro schrieb:>> Wenn man meint nur Einfachvererbung und Interfaces zu brauchen, kann man>> das in jedem C++ Projekt jederzeit so machen. Gibt ja abstrakte>> Basisklassen als Interface.>> Aber diese lösen dass Diamond-Problem nicht, oder?> https://de.wikipedia.org/wiki/Diamond-Problem
Mit virtueller Vererbung geht das.
Also anstelle
class B : public A
class C : public A
einfach
class B : public virtual A
class C : public virtual A
verwenden.
Jan H. schrieb:> Rolf M. schrieb:>> Nicht nur main(). Teils gibt es auch Hilfsfunktionen, die eigentlich>> freistehend sein sollten. In Java muss man die auch irgendwie in>> Dummy-Klassen zusammenfassen. Eine Klasse, die niemals instanziiert wird>> und von der auch nie geerbt wird, geht für mich irgendwie am Sinn von>> Klassen vorbei.>> Es sollte so wenig wie möglich freistehend = global sein. Ist doch> absolut sinnvoll, Hilfsmethoden zu strukturieren und zu verpacken.
In C++ gibt's dafür Namespaces. Da muss man nicht extra eine
Pseudoklasse für erstellen.
> Man muss eben nicht alles in instanziierte und sieben Mal abgeleitete und> Interfaceüberladene Methoden stecken.
Muß man nicht, aber dann gehört es eben auch nicht in eine Klasse.
Axel S. schrieb:>> Das ist nicht die einzige Ausnahme. C hat sich unabhängig von C++>> weiterentwickelt, und so gibt es auch C-Features, die C++ so nicht hat,>> z.B. VLAs.>> Du beliebst zu scherzen. VLA sind im GCC schon seit Ewigkeiten als> Erweiterung drin. Und funktionieren selbstverständlich in C++ genauso> wie in C
In C++ sind sie allerdings eine nicht-Standard-Erweiterung. In C gehören
sie zum Sprachumfang dazu. Es ging um die pauschale Behauptung, jedes
C-Programm sei automatisch auch ein C++-Programm. Wenn man beliebige
Erweiterungen akzeptiert, gilt das natürlich immer.
> /tmp $gcc -std=c99 test.c -o test_c>> /tmp $g++ test.c -o test_c++
Hmm, für C schaltest du also explizit Konformität zur Norm ein, für C++
nicht. Wenn du das da auch tätest (z.B. -std=c++11), sähe es anders aus.
Ulrich F. schrieb:> Mehrfachvererbung bringt auch so seine Probleme mit sich...> Es wurde in C++ eingebaut, aber ich glaube, dass sich die Entwickler> immer noch reihenweise dafür selber in den Arsch beißen.
Also ich finde sie sehr praktisch und beiße mir dafür nirgendwo rein.
Daniel A. schrieb:> * Mir gefällt nicht, dass ich für gewisse Templates die Funktionen> inline im Header in der Klasse haben muss, und so Code und Interface> nichtmehr sauber trennen kann.
Musst du doch nicht. Du kannst da auch die Implementation in ein
separates File schreiben. Nur die Art, wie es eingebunden werden muss,
ist anders.
> und dann kann man Klassen nichteinmal in ein extern C setzen...
Wie soll das auch gehen? Klassen unterstützt C nicht.
Rolf M. schrieb:> Jan H. schrieb:>> und dann kann man Klassen nichteinmal in ein extern C setzen...> Wie soll das auch gehen? Klassen unterstützt C nicht.
extern "C" verändert die C++ Linkage, aber es bedeutet nicht dass nun
C-Code folgt.
Falls dem nicht so ist lass ich mich gerne aufklären.
Johann L. schrieb:> Rolf M. schrieb:>> Jan H. schrieb:>>> und dann kann man Klassen nichteinmal in ein extern C setzen...>> Wie soll das auch gehen? Klassen unterstützt C nicht.>> extern "C" verändert die C++ Linkage, aber es bedeutet nicht dass nun> C-Code folgt.
Nein, aber es folgt Code, der direkt so von C aus aufgerufen werden
kann. Wie soll man von C aus denn die Klasse instanziieren? Wie soll man
ihre Member aufrufen? Wie soll der C-Compiler dafür sorgen, dass die
Destruktoren aufgerufen werden, wenn die Instanz zerstört wird?
Rolf M. schrieb:> Wie soll man von C aus denn die Klasse instanziieren?
Manuell, also z.B.
1
structKlassx;
2
Klass_construct(x);
Man nimmt einfach ein Struct mit den selben Membern in der selben
Reihenfolge. Mit ein wenig Präprozessormagie ist das kein Problem
> Wie soll man ihre Member aufrufen?
Man müsste auf virtuelle Methoden und überladung verzichten, aber
ansonsten würde man aus x.y(z) ein z(x,y).
> Wie soll der C-Compiler dafür sorgen, dass die Destruktoren aufgerufen werden,> wenn die Instanz zerstört wird?
Garnicht, man macht es Manuell:
1
Klass_denstruct(x);
Ich musste ewig suchen, aber es folgt ein Link, wo ich eine
Binärkompatible c version einer C++ Klasse Präsentiere:
Beitrag "Re: This Pointer"
Daniel A. schrieb:> * Komplexität, Beispiel: lvalue, rvalue und rvalue referenzen, ich will> möglichst jeden Kopiervorgang und Redundanz verhindern. Eine Funktion> soll deshalb sowohl eine lvalue als auch eine rvalue als Argument nehmen> können; Verwende ich keine Referenz als Argumenttype, wird Kopiert.> Verwende ich eine, kann ich keine rvalue übergeben. Verwende ich eine> rvalue-referenz, kann ich keine lvalue mehr übergeben, und überlade ich> die Funktion, gibt es uneindeutige Situationen. Ein schönes Happy End> gibt es nicht, entweder man nutzt die Kopierveriante, oder die Referenz> variante und speichert rvalues in lvalues vor dem Aufruf...
Ja rvalues sind kompliziert aber deine Erläuterungen stimmen nicht ganz.
Wenn deine Funktion sowohl lvalues als auch rvalues nehmen soll, dann
nimmt man einfach eine normale (lvalue) const Referenz. Oder wenn du
sowieso eine Kopie brauchst dann einfach Call by Value. Der Fall das man
die gleiche Funktion mit lvalue und rvalue Referenz braucht tritt meiner
Meinung nach eher selten auf und dann ist auch nichts uneindeutig.
Daniel A. schrieb:> Rolf M. schrieb:>> Wie soll man von C aus denn die Klasse instanziieren?>> Manuell, also z.B.struct Klass x;> Klass_construct(x);>> Man nimmt einfach ein Struct mit den selben Membern in der selben> Reihenfolge. Mit ein wenig Präprozessormagie ist das kein Problem
Was hat das jetzt mit einer Klasse, die extern "C" ist, zu tun?
Natürlich kann man sich einen Wrapper schreiben, um Klassen zu benutzen.
Darum ging's aber gar nicht. Es ging viel mehr um die Frage, warum
Klassen nicht extern "C" sein können. Und meine Antwort war, daß C gar
keine Syntax bietet, um die zu nutzen und es daher gar keinen Sinn
ergibt.
@Sebastian V. O. (sebi_s)
Danke für die Erlauterung, ich wusste nicht, dass dies möglich ist, da
man ja keine Referenz von einer rvalue nehmen kann habe ich dies vorher
nie ausprobiert.
@Rolf Magnus (rmagnus)
Wenn man dadurch das Name Mangeling der Methoden der Klassen abschalten
könnte, könnte man mit 2 Macros standardisierte Wrapper für Klassen auf
C-Strukts machen, und ich denke dies wäre speziell bei Libraries extrem
nützlich.
Rolf M. schrieb:> Axel S. schrieb:>>> Das ist nicht die einzige Ausnahme. C hat sich unabhängig von C++>>> weiterentwickelt, und so gibt es auch C-Features, die C++ so nicht hat,>>> z.B. VLAs.>>>> Du beliebst zu scherzen. VLA sind im GCC schon seit Ewigkeiten als>> Erweiterung drin. Und funktionieren selbstverständlich in C++ genauso>> wie in C>> In C++ sind sie allerdings eine nicht-Standard-Erweiterung. In C gehören> sie zum Sprachumfang dazu. Es ging um die pauschale Behauptung, jedes> C-Programm sei automatisch auch ein C++-Programm.
Ich sehe schon, es war ein Fehler, überhaupt auf diesem Nebenkriegs-
schauplatz zu erscheinen. VLA braucht man in C++ kein Stück. Container
mit zur Laufzeit wählbarer Größe sind in jeder OO Programmiersprache
eines der der ersten Konstrukte. Wenn man also in einem C-Programm ein
VLA verwendet und das dann der C++ Compiler nicht fressen mag, ist es
eine der leichtesten Übungen, ein funktionales Äquivalent mit C++
Hausmitteln dafür einzusetzen.
Aber wie gesagt: Nebenkriegsschauplatz. Per Design ist C++ so nah an C
wie überhaupt nur möglich. Und deswegen ist jede Behauptung, man müsse
in C++ komplizierter (mit C++ Sprachmitteln) programmieren als in C,
auch vollkommener Unsinn.
Man kann in C++ genauso programmieren wie in C. Wieviel Sinn das ergibt
und wieviel Potential man damit verschenkt, das steht natürlich auf
einem anderen Blatt.