C++ und C# unterschied?

3 Antworten

Das ist, wie als würdest Du Die Plastik-Kügelchen mit den fertigen Legosteinen vergleichen :D Der Vergleich hinkt, ich weiß, was ich sagen will: Die Syntax ist ähnlich, das ist aber auch das Einzige. Technologisch sind beide Sprachen zwei vollständig verschiedene Dinge ;)

C++ wird in Assembly kompiliert und arbeitet direkt "auf" der Hardware, man hat entsprechend viele Möglichkeiten, muss aber auch entsprechend viel beachten und sehr viele Details selber machen, bzw. es gibt wenig Hilfestellungen oder Vereinfachungen.

C# wird in eine "Zwischensprache" (nennt sich "CIL") kombiliert, das wird wiederum live von einer eigenen Laufzeit kompiliert und ausgeführt, die dabei auch viel Sicherheit bieten und viele leidige Aufgaben (z.B. Speichermanagement) übernehmen kann. Du hast somit weniger Möglichkeiten, aber die Arbeit an sich ist viel einfacher.
Die Einschränkungen von C# sind aber nicht so groß, wie es klingt, die findet man eher im Detail, wenn man z.B. direkt Treiber nutzen möchte.

Die Unterschiede im Bezug auch Objektorientierung, Framework, etc. lasse ich Mal unbeachtet, die sind irrelevant, im Vergleich zu den technischen Unterschieden :D

Wenn ich eine Anwendung entwickeln müsste, die sehr hardwarenahe arbeiten soll, dann würde ich beides nutzen. Ein kleines in C++ entwickeltes Framework, das die eigentlichen Funktionen an der Hardware umsetzt, parallel dazu eine C# Anwendung, die dieses C++-Framework nutzt.

Woher ich das weiß:Beruf – C# Softwareentwickler seit 2013

Ja, da gibt es große Unterschiede, schon alleine, weil es in C#/.NET keine Pointer gibt. Syntaktisch nicht so sehr (beide sind zumindest ähnlich), aber im Detail dann doch und vor allem im kompletten Framework. Außerdem ist C# komplett objektorientiert, C++ nicht unbedingt.

gibt doch pointer in c# oder irre ich mich da?

1
@Tyldu

Da irrst Du teils ;-)

Man kann, wenn man es explizit aktiviert, mit unsafe code arbeiten, womit man etwas ähnliches erhält wie Pointer.

Weiterhin gibt es mit IntPtr einen Typ für Systempointer, aber die funktionieren aus C#-Sicht anders als C++ Pointer.

Das, wofür man in C++ Pointer verwendet, ist in C#/.NET gegeben dadurch, dass Objekte Referenzen sind.

2
@ohwehohach
Das, wofür man in C++ Pointer verwendet, ist in C#/.NET gegeben dadurch, dass Objekte Referenzen sind.

Nur als Überlegung, nicht als Ergänzung und schon gar nicht als Anmerkung: Meines Erachtens nur teilweise durch Objektreferenzen. Teilweise auch durch delegates (Funktionszeiger), teilweise durch Container (wenn man an die C++-Pointer-Konzepte p** und p*** denkt - oder shared_ptr< shared_pointer <> > etc., um in selbst gebastelten Container zwischen die Elemente zu kommen) , teils sonstwie sofern in NET überhaupt möglich, teilweise will man Pointer in C# schlicht nicht haben. Die Pointer in den Compiler-Sprachen sind schon eine radikale, megamächtige Sache.

1
@nobytree2

Dafür ist mein C++ nicht gut genug ;-) Ja, Pointer sind mächtig, aber Pointer sind auch gefährlich. Speicherlecks sind da noch das harmloseste...

Ich bin in 99,9% der Fälle ganz froh, dass ich mich in C#, Swift, Java, Kotlin und Co. damit nicht mehr quälen muss.

1
@ohwehohach

Beispiel Array:

In C# ist das eine Liste mit fester Länge und Typ. Wenn man auf einen Wert außerhalb dieses Bereichs zugreift, gibt's eine Exception.

Bei C++ ist das ein Startpunkt und die im Speicher relevante "Länge" der Werte. Wichtig ist hier, wie C++ auf die einzelnen Wert zugreift:

Startposition im Speicher + (Größe pro Wert * Index)

Das ist natürlich nicht vollständig, mir geht's um das Grundprinzip und das Problem dabei, was passiert, wenn der Index größer ist, als das Array? In C# kriegst Du einen Fehler, in C++ kriegst Du den Wert hinter dem Array, was auch immer das in dem Fall sein mag.

Lustig wird's, wenn ein Programm funktioniert, WEIL hinter einem Array auf einmal der richtige Wert steht, denn Du findest nie im Leben den Fehler, wenn da Mal NICHT der richtige Wert steht :D

Oder was passiert, wenn Du dort hin schreibst? Joa, Du überschreibst von irgendetwas Anderem die Daten, Mal gucken, was das Andere dann tut, wenn es da plötzlich andere Daten findet, als erwartet.

PS:

Ich bin kein C++-Experte, aber ich kannte Mal einen und hab ihm gerne zugehört :D

0
@Palladin007

War das als Erweiterung von möglichen Problemen mit Pointern an den Fragesteller gedacht? Ansonsten: Ich weiß :-D

0

Allenfalls die Syntax im Code (mit Ausnahme von WPF) recht ähnlich, ansonsten gibt es eigentlich nur Unterschiede:

C++ ist aus C entstanden, C wurde für die Betriebssystemprogrammierung Unix entworfen, liest sich manchmal so wie eine Makrosprache für Assembler. C++ (es müsste ++C heißen) ist eine Erweiterung anfangs um Objektorientierung, inzwischena auch um sehr viele gute Bibliotheken für eine Hochsprache. Die Wurzeln sind jedoch sehr spürbar. C++ ist äußerst mächtig und kompliziert zu programmieren, man kann auch direkt in die Hardware "greifen".

C# ist die Microsoft-Lösung zu Java, hat also mit C++ eigentlich null zu tun. Es ist einer Kombination aus Interpreter und Compiler, eine Art Sandkastensprache (kein Griff in das System oder in die Maschine), stark auf Windows bezogen, also eine Sprache über die GUI-Schnittstellen. Es ist aber - wie Java - eine OOP-Sprache (vom Konzept, aber nicht so radikal wie Java), welche schnell Anwendungen ermöglicht. Dann haben wir WPF, wir haben die Möglichkeit, uns Fenster zusammenzuziehen, wir haben viele Bibliotheken, auch viele GUI-Bibs.

Woher ich das weiß:Eigene Erfahrung – Hobby und teilweise beruflich
Es ist aber - wie Java - eine OOP-Sprache (vom Konzept, aber nicht so radikal wie Java)

Aus Interesse: Was meinst Du damit? Also inwiefern ist Java strikter?

Und ich möchte nur für das Verständnis des Fragestellers anmerken, dass WPF, Forms und Co mit der Programmiersprache C# gar nichts zu tun haben.

Da diese ganzen Frameworks nämlich Teil von .NET sind oder eben in einer .NET Sprache geschrieben wurden, können sie generell in jeder .NET Sprache auch verwendet werden.

Zudem kannst Du eine komplette Anwendung mit GUI und Klimbim auch einfach "hinschreiben". Die Designer sind Teil der Entwicklungsumgebung.

1
@ohwehohach

Java kennt nur Objektorientierung. Es gibt nur ganz wenige Ausnahmen und das sind die vordefinierten Typen, wie z.B. int. Da kommt man auch nicht raus, wenn z.B. komplexere Dinge mit einem Int machen will, muss man eine Instanz der Klasse Integer erstellen. Die Instanz bietet dann zwar die Funktionen, ist am Ende aber nur ein Wrapper um die eigentliche Zahl.
In Java kann man aber nicht einfach hin gehen und ein Struct bauen und damit die Objektorientierung umgehen.

So gesehen befindet sich C# zwischen C++ und Java. Es ist ebenfalls sehr streng objektorientiert, aber es Wege, das zu umgehen oder ohne Objektorientierung zu arbeiten.

C++ arbeitet intern nur mit Structs. Der Compiler ist bloß so klug, die Klassenzugriffe soweit umzubauen, dass daraus Funktionspointer und Pointer auf den "Instanz"-Wert werden.Was der Compiler im Detail daraus macht, weiß ich nicht, aber wenn man etwas damit arbeitet, merkt man, dass es nur so "halb objektorientiert" ist.

1
@ohwehohach

Beispiel für da radikale OOP-Denken von Java: Es gibt z.B. keine Delegates in Java. Statt dessen muss in Java ein Objekt kreiert werden, welches nur eine Methode hat. (Es gibt wohl noch so etwas wie reflections). Weil es in Java nur Objekte gibt mit Ausnahme von den primitiven Typen wie int, double, Long etc. Aber natürlich gibt es davon auch Objektversionen mit Wrapper. Das war mir dann zu viel des Guten. So etwas wie "Hallo".MethodeABC() ist mir schon suspekt, das ist schon fast wie 1234,567.MethodeXYZ(). Und lamda laufen bei Java ggf. auch nur via Objekte, bin aber nicht sicher. Bei Java muss gefühlt alles irgendwie Objekt sein. Schon dieser Aufbau in Java, main muss Teil eines Objekts sein. Dann dieses static in Java, um global etwas zu definieren.

Man kann natürlich alles in C# hinschreiben; Forms und WPF werden aber nicht direkt in bearbeitbaren Code übersetzt (zumindest wäre mir das entgangen, lasse mich aber gerne belehren).

0
@nobytree2

Thema Forms:

Doch, Forms ist 100% bearbeitbarer Code, schau dir die Designer.cs an, die wird vom Designer gelesen und geschrieben. Bearbeite dort und der Designer übernimmt das.
Einziger Knackpunkt: Der Designer kommt vielleicht nicht mit allem klar oder überschreibt Änderungen von dir.

Thema WPF:

WPF kann genauso genutzt werden, wie WinForms, nur etwas weniger komfortabel. Eine Designer.cs gibt's hier nicht, es gibt nur generierte Klassen um z.B. die InitializeComponent-Methode, oder Variablen zu den benannten Controls zu bieten.
Im Hintergrund wird aus XAML aber BAML, ein Binärformat, das in der InitializeComponent-Methode gelesen und interpretiert wird. Dabei werden auch besagte Variablen instanziiert. Das BAML-Format ist aber nicht notwendig, es ist bloß performanter zu lesen und zu interpretieren, man kann es genauso wieder in XAML zurück "dekompilieren".
Der Designer schreibt hier den XAML-Code und die generierten CS-Dateien. Beides kann man bearbeiten, Letzteres würde aber überschrieben werden.

So oder sind aber beides nur Frameworks mit Unterstützung aus der IDE, man kann sie auch vollständig Ohne nutzen, man kann auch XAML zur Laufzeit interpretieren und nutzen, oder man baut sich in WPF auch eine Designer.cs wie in WinForms.

Das alles ist aber nicht C#-spezifisch, da hat ohwehohach schon recht ;)
Theoretisch wäre das auch für jede andere Sprache möglich, ist bloß verdammt viel Arbeit.

2
@nobytree2

Aber in C# ist ein Delegate auch ein Objekt. Was man schon daran sieht, dass er Methoden hat wie "Invoke" oder "BeginInvoke".

Das mit primitiven Datentypen und den dazu gehörenden Objekttypen ist in C# genauso. Auch, dass die Main-Methode Teil einer Klasse sein muss.

Du kannst in C# nichts (aber auch gar nichts) außerhalb eines Objekts definieren.

Dann dieses static in Java, um global etwas zu definieren.

Static hat nichts mit Globalität zu tun. Auch ein static Member ist immer Teil einer Klasse.

Was structs angeht, die gibt es in Java in der Tat nicht. Der Unterschied zu einer Klasse ist aber lediglich, dass structs Werttypen darstellen, während Klassen Objekttypen darstellen und structs auf dem Stack liegen, während Objekte auf dem Heap liegen.

Sorry, das ging auch an @palladin.

0
@Palladin007

Ich wüsste jetzt nicht, wie man in C# die Objektorientierung umgehen sollte. Es ist alles ein Objekt und es gibt nichts außerhalb von Objekten. Ein struct ist hierfür kein gutes Beispiel, denn es hebt nicht die Objektorientierung auf.

0
@ohwehohach

Auch an ohwehohach

Ein Delegate ist eine eigene Klasse, aber die nutzt intern die Pointer, wie in C++. So gesehen ist es kein Objekt, die Delegat-Instanz ist ein Wrapper darum.
Allerdings kannst Du die Art (Objekt, kein Objekt) nicht daran fest machen, ob es Methoden hat, denn die vordefinierten Typen haben entsprechend dazu passende Structs, die im Hintergrund gleichgesetzt werden.
Das lässt sich aber nicht mit den gängigen Konzepten von C# erklären, da hat die Runtime ihre Finger im Spiel, was die genau tut, weiß ich auch nicht.

Thema Struct/Klasse:

Kommt drauf an, wie Du Objektorientierung definierst. In der OOP gibt es verschiedene Konzepte, eine Klasse erfüllt die alle, ein Struct erfüllt nur die Kapselung, Polymorphie und Vererbung sind nicht möglich.

Genauso kann man aber auch bei Klassen die Vererbung mit dem "new"-Operator bei Methoden aushebeln - einfach gesagt.

Nur weil alles von Object ableitet, ist nicht alles streng objektorientiert, Microsoft hat bloß die Klasse so genannt, um eine gemeinsame Basis zu haben.
Parallel dazu gibt es noch weitere Konzepte, wie DuckTyping (dynamic), allerdings sind die kein Widerspruch zur Objektorientierung.

PS:

Ich habe nie gesagt, dass man die Objektorienierung umgehen sollte, aber man kann es tun und es macht in einigen Fällen auch Sinn ;) Das sollte man sich dann aber immer sehr genau überlegen.

0
@Palladin007
Polymorphie und Vererbung sind nicht möglich.

Das stimmt wiederum, da hast Du Recht.

Ein Delegate ist eine eigene Klasse, aber die nutzt intern die Pointer, wie in C++. So gesehen ist es kein Objekt, die Delegat-Instanz ist ein Wrapper darum.

Aber tut das ein normales Objekt (sowohl in .NET als auch in Java) nicht auch? Im Wesentlichen ist es im Hintergrund auch ein Pointer mit einer VMT und Co. Nur heißt es in .NET eben nicht Pointer, sondern Referenz und hat eben nicht alle Möglichkeiten eines Pointers.

Genauso kann man aber auch bei Klassen die Vererbung mit dem "new"-Operator bei Methoden aushebeln - einfach gesagt.

Naja, das geht ja in Java prinzipiell auch, indem man eben einfach nicht "super.methode()" aufruft. In Java wird grundsätzlich erst einmal überschrieben. Es gibt kein explizites override, weil alles ein override ist.

In C# ist der default aber "new". Lässt man das "new" weg, gibt's eine Warning, wenn es das Member in diese Form bereits in der Basisklasse gibt. Will man überschreiben, muss ein explizites "override" hin, ansonsten wird "verdeckt" mit Warnung. "new" macht nur, dass die Warnung weggeht und beim Lesen schon klar ist, dass ein Member der Basisklasse verdeckt wird.

Allerdings verwende ich das so selten, dass ich gerade nicht weiß, ob das noch andere Auswirkungen (z.B. auf Polymorphie) hat.

Ich habe nie gesagt, dass man die Objektorienierung umgehen sollte, aber man kann es tun und es macht in einigen Fällen auch Sinn ;) Das sollte man sich dann aber immer sehr genau überlegen.

Das hatte ich auch so nicht verstanden! Ich finde nur gerade die Diskussion interessant darüber, was .NET "weniger objektorientiert" macht als Java.

0
@ohwehohach
Aber tut das ein normales Objekt (sowohl in .NET als auch in Java) nicht auch?

Stimmt. Java könnte das vermutlich auch umsetzen, ohne ihr Konzept zu verlassen, warum sie es nicht tun, weiß ich nicht.

Der Unterschied ist also ziemlich simpel: C# bietet diese Möglichkeit, Java nicht.

Ganz so simpel kann man diese systemnahen Klassen von .NET aber nicht sehen, denn die holen sich sehr häufig "Hilfe" von der Runtime. Im Source von .NET sieht man die Methode dann als "extern" markiert und mit "MethodImplOptions.InternalCall".
Was da im Hintergrund passiert, wüsste ich sehr gerne, aber noch hab ich keinen halbwegs übersichtlichen Weg gefunden, den Source der dazugehörigen Runtime-Methode zu bekommen :/

Naja, das geht ja in Java prinzipiell auch, indem man eben einfach nicht "super.methode()" aufruft.

Nur ist "new" kein Überschreiben der Methode ohne Base-Aufruf. "new" verbirgt sozusagen die Base-Methode, eine solche Methode kannst Du explizit nur aufrufen, wenn die Variable auch den richtigen Typen hat.
Beim Überschreiben (override) wäre immer noch egal, mit welchem Typen Du arbeitest, Du bekommst immer die überschriebene Variante, egal, ob nun die Base aufgerufen wird, oder nicht.

Das "new" ist also das exakte Gegenteil von "override". Ich verwende es auch nur sehr, sehr selten und in fast allen Fällen ist es schrecklich falsch :D

public class MyBase
{
    public virtual void TestOverride()
        => Console.WriteLine("Override Base");

    public virtual void TestNew()
        => Console.WriteLine("New Base");
}
public class MyChild : MyBase
{
    public override void TestOverride()
        => Console.WriteLine("Override Child");

    public new void TestNew()
        => Console.WriteLine("New Child");
}

MyBase varBase = new MyChild();
MyChild varChild = new MyChild();

varBase.TestOverride(); // Override Child
varBase.TestNew(); // New Base

varChild.TestOverride(); // Override Child
varChild.TestNew(); // New Child

Beide Instanzen haben den Typ der Ableitung, beim Aufruf von "TestNew" wird aber relevant, welchen Typ die Variable hat. Das "virtual" bei "TestNew"-Methode ist aber eigentlich egal.

Das hatte ich auch so nicht verstanden! Ich finde nur gerade die Diskussion interessant darüber, was .NET "weniger objektorientiert" macht als Java.

.NET ist nicht weniger objektorientiert in dem Sinne, es bietet aber mehr Möglichkeiten, von den streng objektorientierten Wegen abzuweichen.

Ach ja, Thema Lambda:

In C# gibt's davon zwei Variante. Die "normalen" Lambdas sind einfach nur Methoden, die vom Compiler erstellt werden, mit Klassen, um die Variablen zu halten.
Daneben gibt's die Lambda-Ausdrücke (Expressions), die sind im Hintergrund komplexe Objekte, die jede Kleinigkeit des Lambda-Ausdrucks per Reflection beschreiben. Dieses Objekt wird zur Laufzeit zusammengebaut, man man kann es dann interpretieren und z.B. zur Laufzeit kompilieren und ausführen - deshalb sind sie auch so langsam, aber unglaublich nützlich.

Wie das bei Java läuft, weiß ich allerdings nicht.

0
@Palladin007
Beide Instanzen haben den Typ der Ableitung, beim Aufruf von "TestNew" wird aber relevant, welchen Typ die Variable hat. Das "virtual" bei "TestNew"-Methode ist aber eigentlich egal.

Ah, siehste? Das meinte ich mit "weiteren Auswirkungen". Im Prinzip hebelt man mit "new" also die Polymorphie aus. Das war mir so nicht klar, weil ich das quasi noch niemals verwendet habe.

0
@ohwehohach

Deshalb hab ich es etwas ausführlicher beschrieben :)

Allerdings hast Du mit "noch nie verwendet" auch nichts falsch gemacht :D Die paar Fälle, wo ich es nutze, sind auch nur Syntaxzucker, weil ich kein Bock hab, ständig zu casten :D

public class MyBase
{
    public object Value { get; }
 
    public MyBase(object value)
    {
        Value = value;
    }
}
public class MyChild<TValue> : MyBase
{
    public new TValue Value
    {
        get => (TValue)base.Value;
    }
 
    public MyChild(TValue value)
        : base(value)
    {
    }
}
0

Was möchtest Du wissen?