Asi tak každých deset let se objevuje nový styl programování. V osmdesátých letech to byl Unix a programovací jazyk C, v devadesátých Windows a C++, nyní je výhodné se naučit jazyk C# a .NET Framework. Tento článek nepopisuje základy jazyka C#, ale zaměřuje se na rozdíly jazyka C# a C++ a je tedy určen zejména pro zkušenější C++ programátory.
Co nás tedy v tomto novém jazyce může překvapit?
Hlavním rozdílem je existence .NET Frameworku. Pokud nevíte, o co jde, rozhodně vám doporučuji si o .NET Frameworku něco přečíst. V krátkosti můžeme říci, že se jedná o platformu, nad kterou se spouštějí programy napsané například v jazyce C#. .NET Framework lze přirovnat k Java Runtime, ale samozřejmě existuje mnoho větších či menších rozdílů. Podobný je například přístup ke správě paměti, kde se stejně jako v jazyce Java používá algoritmus Garbage Collection. Tento algoritmus patří do velké množiny funkcí a služeb, které tato platforma poskytuje. Odtud také vyplývá většina rozdílů mezi C++ a C#. Tyto rozdíly jsou povahy spíše konceptuální a jsou na první pohled dobře patrné. My se ale zaměříme spíše na rozdíly kosmetičtější, o to ale skrytější a záludnější.
Ještě bych rád upozornil, že článek si v žádném případě nedělá nárok na úplnost. Rozdílů mezi těmito dvěma jazyky existuje jistě velké množství a jejich sepsání a podrobný rozbor vydá přinejmenším na jednu knihu. Zde jsou shromážděny a ukázány jen hlavní z nich.
Syntaxe
Jazyk C# obsahuje podobně jako Java pouze jeden typ souborů se zdrojovým kódem. V jazyce C# mají příponu .cs. Neexistují tedy hlavičkové soubory.
C# nepodporuje makra. Lze tak podstatně zrychlit práci překladače JIT, který nemusí skládat výsledný kód z mnoha různých částí.
Funkce Main() začíná velkým písmenem.
Datové typy
Neexistuje datový typ pointer. Místo toho se všude používá reference.
Reference může mít hodnotu null. Přesněji řečeno reference je na tuto hodnotu automaticky inicializována.
Třída je datového typu reference, tj. nelze vytvořit třídu umístěnou na zásobníku. Zápis:
MyClass class;
vytvoří pouze instanci typu reference nastavenou na null. Třída samotná vznikne až voláním:
class = new Class();
Jednoduché datové typy jsou namapovány na speciální třídy (např. int je namapován na System.Int32) a pokud je to třeba, může se s nimi pomocí speciálního algoritmu zvaného boxing a unboxing pracovat jako s objektovými typy.
int value = 2;
string s = value.ToString();
Datový typ int zde byl automaticky převeden na datový System.Int32. Tím pádem získal metodu ToString.
Datový typ bool se automaticky nekonvertuje na typ int. Díky této vlastnosti jazyk nepovolí konstrukci typu:
if (c = 5)
která bývá velmi často chybou.
Struktury jsou považovány za jednoduché datové typy, jako parametry se předávají hodnotou a nelze je dále rozšiřovat a použít jako základ pro dědění třídy.
Neexistují konverzní konstruktory tříd.
Vícedimenzionální pole jsou dvojího typu. Buď „pravoúhlá“:
int[,] arr = new int[5, 2];
nebo definovaná jako pole polí, kde každé pole může mít jinou velikost:
int[][] arr = new int[5][];
arr[0] = new int[3];
arr[1] = new int[4];
Přibyl datový typ decimal, který by se měl používat pro monetární operace.
Typ string řeší operace s řetězci. Přestože jde o třídu, nelze od něj dále dědit a má předdefinován operátor porovnávání, takže se ve výrazu:
if (string1 == string2)
porovnávají skutečné hodnoty řetězců a ne reference.
Deklarace, definice
Neexistují globální proměnné.
Deklarace třídy není ukončena středníkem.
Nerozlišuje se mezi deklarací a definicí metody. Všechny metody jsou deklarovány inline, tj. jejich kód se píše rovnou do deklarace třídy.
Pořadí tříd v souboru je libovolné, programátor nemusí řešit vzájemné vztahy mezi třídami a případně vytvářet tzv. dopředné deklarace (forward declarations) – lze např.:
class A
{
B b;
}
class B
{
A a;
}
Neexistuje typedef.
Viditelnost členů třídy se určuje před každým členem, například:
class C
{
private char c;
public int valueint;
}
Parametry, proměnné
Všechny proměnné musí být před použitím inicializované. Pokud se v kódu použije neinicializovaná proměnná, ohlásí překladač chybu.
int a, b;
a = b;
// chyba
Nelze inicializovat členy třídy v hlavičce třídy, ale lze je inicializovat v deklaraci třídy
class A
{
protected int a = 4;
}
Neexistují konstantní parametry funkcí.
Implicitní (default) parametry funkcí nejsou podporovány
Parametry funkcí, které jsou jednoduchého datového typu (int, char), se stejně jako v C++ předávají hodnotou. Pokud jsou ale označeny jako ref nebo out, předávají se referencí. Modifikátor out způsobí předání hodnoty pouze jednosměrně „ven“ z funkce, takže lze tímto způsobem inicializovat proměnné.
class X
{
protected int m_x = 0;
public void GetRef(ref int x)
{
x = m_x;
}
public void GetOut(out int x)
{
x = m_x;
}
}
// ...
X x = new X();
int value;
// nasledujici radka je chybna, x1 neni inicializovana
x.GetRef(ref value);
// nasledujici radka je v poradku
x.GetOut(out value);
Příkazy
V příkazu switch musí být všechny větve ukončené příkazem break.
V příkazu switch se lze rozhodovat i podle proměnné typu string.
Přidán příkaz foreach pro postupné procházení kolekcí. Příkaz funguje podobně jako v jazyce Visual Basic.
// vypsani parametru prikazove radky
static void Main(string[] args)
{
foreach(string arg in args)
Console.WriteLine(arg);
}
Objektové vlastnosti
Neexistuje vícenásobná dědičnost, ale jedna třída může implementovat více rozhraní.
Pro přístup k datovým členům tříd a volání metod včetně statických, se používá operátor tečka „.“ a jsou vypuštěny operátory „::“ a „->“.
Virtuální metody musí být při implementaci v odvozené třídě explicitně označeny klíčovým slovem overridde.
Virtuální metodu lze v odvozené třídě skrýt pomocí new.
Abstraktní metody jsou označeny klíčovým slovem abstract.
Statické metody třídy nelze volat z objektu, tedy instance třídy.
Lze vytvořit tzv. indexer a pak k instanci třídy přistupovat pomocí indexu [] jako k poli hodnot.
Třídy nemají destruktor, místo toho mají tzv. finalizer. Rozdíl oproti destruktoru je, že finalizer se volá (pokud vůbec), až když je objekt uvolněn z paměti algoritmem Garbage Collection.
Pořadí a čas uvolnění objektů z paměti nelze přesněji určit a nemůžeme se tedy na ně spoléhat.
Ze tříd označených jako sealed nelze vytvářet děděním odvozené třídy.
Třídy podporují vlastnosti (properties) – podobně jako v technologii COM.
class A
{
int m_a;
// vlastnost a
public int a
{
get
{
return m_a;
}
set
{
m_a = a;
}
}
}
// ...
// pouziti vlastnosti a
A local = new A():
local.a = 5;
Console.WriteLine(“{0}“, local.a);