Last modified: September 25, 2024
This article is written in: 馃嚨馃嚤
C vs C++
C i C++ to dwa j臋zyki programowania o wsp贸lnych korzeniach, kt贸re odgrywaj膮 kluczowe role w dziedzinie informatyki. Chocia偶 C++ jest cz臋sto okre艣lany jako rozszerzenie C, r贸偶nice mi臋dzy nimi s膮 na tyle znacz膮ce, 偶e warto je szczeg贸艂owo om贸wi膰. W poni偶szym tek艣cie przedstawimy dog艂臋bn膮 analiz臋 obu j臋zyk贸w, zwracaj膮c uwag臋 na ich histori臋, zgodno艣膰, sk艂adni臋, funkcjonalno艣ci oraz zastosowania, z naciskiem na rygor matematyczny i techniczny.
Historia
J臋zyk C
J臋zyk C zosta艂 opracowany na pocz膮tku lat 70. XX wieku przez Dennisa Ritchiego w Bell Laboratories. By艂 on ewolucj膮 wcze艣niejszych j臋zyk贸w, takich jak B i BCPL. C powsta艂 w celu stworzenia j臋zyka uniwersalnego, kt贸ry umo偶liwi艂by pisanie system贸w operacyjnych oraz program贸w narz臋dziowych z wydajno艣ci膮 zbli偶on膮 do asemblera, ale z wy偶szym poziomem abstrakcji.
Kluczowym momentem w historii C by艂o napisanie systemu operacyjnego UNIX w tym j臋zyku, co przyczyni艂o si臋 do jego szerokiej adopcji. Standaryzacja j臋zyka nast膮pi艂a w 1989 roku wraz z publikacj膮 standardu ANSI C (znanego r贸wnie偶 jako C89), a p贸藕niej w standardach ISO C90, C99, C11 i C18, kt贸re wprowadza艂y kolejne usprawnienia i funkcjonalno艣ci.
J臋zyk C++
C++ zosta艂 stworzony przez Bjarne Stroustrupa w latach 80. XX wieku, r贸wnie偶 w Bell Laboratories. Pocz膮tkowo nazywany "C z klasami", C++ mia艂 na celu wprowadzenie do j臋zyka C mechanizm贸w programowania obiektowego, takich jak klasy, dziedziczenie i polimorfizm. Nazwa "C++" jest odniesieniem do operatora inkrementacji w C, sugeruj膮c, 偶e C++ jest "nast臋pn膮 wersj膮" C.
C++ przeszed艂 wiele etap贸w standaryzacji, pocz膮wszy od standardu C++98, poprzez C++03, C++11, C++14, C++17, a偶 po C++20 i C++23. Ka偶da kolejna wersja wprowadza艂a nowe funkcjonalno艣ci, takie jak szablony (templates), inteligentne wska藕niki, wyra偶enia lambda, koncepty (concepts) i wiele innych, czyni膮c j臋zyk coraz bardziej z艂o偶onym, ale jednocze艣nie pot臋偶nym narz臋dziem do tworzenia skomplikowanych system贸w.
Zgodno艣膰 i R贸偶nice
Zgodno艣膰 Wsteczna
C++ zosta艂 zaprojektowany tak, aby by艂 w du偶ej mierze zgodny wstecz z C. Oznacza to, 偶e wiele kodu napisanego w C mo偶na skompilowa膰 jako kod C++. Jednak偶e ta zgodno艣膰 nie jest absolutna. Istniej膮 subtelne r贸偶nice w semantyce niekt贸rych konstrukcji, co mo偶e prowadzi膰 do nieprzewidywalnych zachowa艅 podczas kompilacji kodu C jako C++.
Na przyk艂ad, w C deklaracje zmiennych musz膮 znajdowa膰 si臋 na pocz膮tku bloku kodu, podczas gdy w C++ mo偶na deklarowa膰 zmienne w dowolnym miejscu. Ponadto, C++ wprowadza nowe s艂owa kluczowe, kt贸re mog膮 kolidowa膰 z identyfikatorami u偶ywanymi w kodzie C.
Typowanie i Bezpiecze艅stwo
C++ wprowadza silniejsze mechanizmy typowania w por贸wnaniu z C. Na przyk艂ad, w C istnieje wi臋ksza swoboda w konwersji wska藕nik贸w mi臋dzy r贸偶nymi typami, co mo偶e prowadzi膰 do b艂臋d贸w. C++ wymaga jawnych rzutowa艅 i wprowadza zestaw operator贸w rzutowania (static_cast
, dynamic_cast
, reinterpret_cast
, const_cast
), co zwi臋ksza bezpiecze艅stwo typ贸w.
Obs艂uga Pami臋ci
W C zarz膮dzanie pami臋ci膮 odbywa si臋 za pomoc膮 funkcji malloc
, calloc
, realloc
i free
. W C++ wprowadzono operatory new
i delete
, kt贸re nie tylko przydzielaj膮 i zwalniaj膮 pami臋膰, ale tak偶e wywo艂uj膮 odpowiednie konstruktory i destruktory obiekt贸w. Dodatkowo, C++ oferuje inteligentne wska藕niki (std::unique_ptr
, std::shared_ptr
), kt贸re automatyzuj膮 zarz膮dzanie zasobami i pomagaj膮 unikn膮膰 wyciek贸w pami臋ci.
Dyrektywy Preprocesora i Za艂膮czanie Bibliotek
W obu j臋zykach u偶ywa si臋 dyrektywy #include
do za艂膮czania plik贸w nag艂贸wkowych. R贸偶nice pojawiaj膮 si臋 jednak w sposobie organizacji bibliotek standardowych.
W C
W j臋zyku C pliki nag艂贸wkowe standardowych bibliotek maj膮 rozszerzenie .h
. Przyk艂ady:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
W C++
W C++ standardowe biblioteki s膮 za艂膮czane bez rozszerzenia .h
, a ich nazwy s膮 zdefiniowane w przestrzeni nazw std
. Dodatkowo, biblioteki C s膮 dost臋pne z prefiksem c
i bez rozszerzenia, np.:
#include <iostream>
#include <vector>
#include <string>
#include <cmath>
// Biblioteki z C w C++
#include <cstdio>
#include <cstdlib>
#include <cstring>
U偶ywaj膮c bibliotek C w C++, nale偶y pami臋ta膰, 偶e ich funkcje s膮 r贸wnie偶 umieszczone w przestrzeni nazw std
.
S艂owa Kluczowe
Wsp贸lne S艂owa Kluczowe
Oba j臋zyki dziel膮 wiele s艂贸w kluczowych, kt贸re s艂u偶膮 do sterowania przep艂ywem programu, deklaracji zmiennych i typ贸w danych:
auto
break
case
char
const
continue
default
do
double
else
enum
extern
float
for
goto
if
int
long
register
return
short
signed
sizeof
static
struct
switch
typedef
union
unsigned
void
volatile
while
Dodatkowe S艂owa Kluczowe w C++
C++ wprowadza szereg nowych s艂贸w kluczowych, kt贸re wspieraj膮 nowe funkcjonalno艣ci j臋zyka:
alignas
alignof
asm
bool
catch
class
const_cast
constexpr
decltype
delete
dynamic_cast
explicit
export
false
friend
inline
mutable
namespace
new
noexcept
nullptr
operator
private
protected
public
reinterpret_cast
static_assert
static_cast
template
this
thread_local
throw
true
try
typeid
typename
using
virtual
wchar_t
Ka偶de z tych s艂贸w kluczowych ma okre艣lon膮 rol臋 w j臋zyku, np. class
i struct
s艂u偶膮 do definiowania nowych typ贸w danych, virtual
umo偶liwia polimorfizm, a template
wprowadza programowanie og贸lne.
Zaawansowane Funkcjonalno艣ci C++
Programowanie Obiektowe
C++ jest j臋zykiem wieloparadygmatowym, kt贸ry wspiera programowanie obiektowe (OOP). OOP wprowadza koncepcje takie jak:
- Klasy i obiekty stanowi膮 podstaw臋 programowania obiektowego, gdzie klasy dzia艂aj膮 jako szablony definiuj膮ce atrybuty i metody, z kt贸rych tworzone s膮 konkretne obiekty.
- Dziedziczenie pozwala na tworzenie nowych klas, kt贸re dziedzicz膮 w艂a艣ciwo艣ci i metody z ju偶 istniej膮cych klas, co umo偶liwia ponowne wykorzystanie kodu.
- Polimorfizm umo偶liwia korzystanie z wska藕nik贸w lub referencji do klasy bazowej, kt贸re mog膮 odnosi膰 si臋 do obiekt贸w klas pochodnych, pozwalaj膮c na elastyczne zarz膮dzanie r贸偶nymi typami obiekt贸w.
- Enkapsulacja zapewnia kontrol臋 dost臋pu do sk艂adowych klasy poprzez ukrywanie szczeg贸艂贸w implementacyjnych i zastosowanie modyfikator贸w dost臋pu, takich jak
private
,protected
ipublic
.
Przyk艂ad definicji klasy w C++:
class Punkt {
private:
double x;
double y;
public:
Punkt(double x = 0.0, double y = 0.0) : x(x), y(y) {}
double odlegloscOdPoczatku() const {
return sqrt(x * x + y * y);
}
void przesun(double dx, double dy) {
x += dx;
y += dy;
}
};
Szablony (Templates)
Szablony umo偶liwiaj膮 tworzenie funkcji i klas generycznych, kt贸re mog膮 dzia艂a膰 z r贸偶nymi typami danych. S膮 one podstaw膮 programowania og贸lnego w C++.
Przyk艂ad szablonu funkcji:
template<typename t="">
T maksimum(T a, T b) {
return (a > b) ? a : b;
}
Szablon klasy:
template<typename t="">
class Wektor {
private:
std::vector<t> dane;
public:
void dodaj(const T& element) {
dane.push_back(element);
}
T pobierz(int indeks) const {
return dane[indeks];
}
};
Obs艂uga Wyj膮tk贸w
C++ wprowadza mechanizm obs艂ugi wyj膮tk贸w, kt贸ry pozwala na kontrolowane zarz膮dzanie b艂臋dami podczas wykonywania programu.
Przyk艂ad u偶ycia wyj膮tk贸w:
double dziel(double a, double b) {
if (b == 0.0) {
throw std::runtime_error("Dzielenie przez zero!");
}
return a / b;
}
int main() {
try {
double wynik = dziel(10.0, 0.0);
} catch (const std::exception& e) {
std::cerr << "Wyst膮pi艂 b艂膮d: " << e.what() << std::endl;
}
return 0;
}
Przeci膮偶anie Funkcji i Operator贸w
C++ pozwala na definiowanie wielu funkcji o tej samej nazwie, ale r贸偶nych sygnaturach (typach i liczbie argument贸w). Przeci膮偶anie operator贸w umo偶liwia definiowanie zachowania operator贸w dla obiekt贸w w艂asnych klas.
Przyk艂ad przeci膮偶ania funkcji:
int suma(int a, int b) {
return a + b;
}
double suma(double a, double b) {
return a + b;
}
Przyk艂ad przeci膮偶ania operatora:
class Liczba {
private:
int wartosc;
public:
Liczba(int wartosc) : wartosc(wartosc) {}
Liczba operator+(const Liczba& inna) const {
return Liczba(this->wartosc + inna.wartosc);
}
};
Referencje
C++ wprowadza referencje, kt贸re s膮 alternatyw膮 dla wska藕nik贸w i pozwalaj膮 na przekazywanie argument贸w do funkcji przez referencj臋, umo偶liwiaj膮c modyfikacj臋 oryginalnych danych bez konieczno艣ci u偶ycia wska藕nik贸w.
Przyk艂ad:
void zwieksz(int& liczba) {
liczba++;
}
int main() {
int x = 5;
zwieksz(x);
// x == 6
return 0;
}
Por贸wnanie Zastosowa艅 i Wydajno艣ci
Zastosowania J臋zyka C
- Programowanie systemowe obejmuje tworzenie system贸w operacyjnych, sterownik贸w urz膮dze艅 oraz kompilator贸w, gdzie wymagana jest niska kontrola nad sprz臋tem i wydajno艣膰.
- Systemy wbudowane dotycz膮 programowania mikrokontroler贸w oraz urz膮dze艅 IoT, gdzie zasoby s膮 ograniczone, a wydajno艣膰 kluczowa.
- Aplikacje o wysokiej wydajno艣ci korzystaj膮 z minimalnego narzutu oraz pe艂nej kontroli nad zarz膮dzaniem pami臋ci膮, co pozwala na maksymalizacj臋 wydajno艣ci.
- Nauka podstaw programowania jest uproszczona dzi臋ki prostocie j臋zyka, co u艂atwia zrozumienie fundamentalnych koncept贸w informatyki.
Zastosowania J臋zyka C++
- Aplikacje wielkoskalowe, takie jak systemy bankowe i aplikacje biznesowe, korzystaj膮 z programowania obiektowego, kt贸re u艂atwia zarz膮dzanie z艂o偶ono艣ci膮 du偶ych system贸w.
- Gry i grafika komputerowa czerpi膮 korzy艣ci z wydajno艣ci C++ oraz dost臋pnych bibliotek, takich jak Unreal Engine, co sprawia, 偶e C++ jest idealnym wyborem w tej dziedzinie.
- Aplikacje z wymaganiami real-time mog膮 korzysta膰 z C++ dzi臋ki mo偶liwo艣ci optymalizacji i pe艂nej kontroli nad zasobami, co jest kluczowe dla tych system贸w.
- Biblioteki i frameworki tworzone w C++ pozwalaj膮 na wykorzystanie szablon贸w i programowania og贸lnego, co umo偶liwia budowanie uniwersalnych i wydajnych narz臋dzi.
Wydajno艣膰
Og贸lnie rzecz bior膮c, zar贸wno C, jak i C++ s膮 j臋zykami kompilowanymi do kodu maszynowego, co zapewnia wysok膮 wydajno艣膰. Jednak偶e:
- Narzut abstrakcji mo偶e wyst膮pi膰 w C++ w przypadku korzystania z funkcji takich jak wirtualne funkcje, wyj膮tki czy RTTI, co mo偶e prowadzi膰 do dodatkowego narzutu czasowego i pami臋ciowego.
- Optymalizacje kompilatora w nowoczesnych kompilatorach pozwalaj膮 na skuteczne optymalizowanie kodu C++, co mo偶e znacznie poprawi膰 wydajno艣膰 aplikacji.
- Kontrola nad zasobami w C++ daje mo偶liwo艣膰 rezygnacji z pewnych funkcji j臋zyka, takich jak polimorfizm, w celu osi膮gni臋cia lepszej wydajno艣ci, co pozwala na bardziej precyzyjne zarz膮dzanie zasobami.
Standardy i Rozw贸j J臋zyk贸w
Standardy C
Standard | Rok | Nowo艣ci |
C89/C90 | 1989 | Pierwszy standard j臋zyka, ustanawiaj膮cy podstawy. |
C99 | 1999 | Nowe typy ca艂kowite (stdint.h ), p臋tle for o zmiennym zakresie, funkcje zmiennowymiarowe, komentarze stylu // . |
C11 | 2011 | Dodaje obs艂ug臋 wielow膮tkowo艣ci, anonimowe struktury i unie. |
C18 | 2018 | G艂贸wnie poprawki do C11. |
Standardy C++
Standard | Rok | Nowo艣ci |
C++98/C++03 | 1998/2003 | Pierwsze standardy, wprowadzaj膮ce szablony, przestrzenie nazw, wyj膮tki. |
C++11 | 2011 | Znacz膮ce rozszerzenia: wyra偶enia lambda, auto , nullptr , inteligentne wska藕niki. |
C++14 | 2014 | Drobne usprawnienia C++11. |
C++17 | 2017 | Nowe biblioteki, std::optional , std::variant , sk艂adnia if constexpr . |
C++20 | 2020 | Koncepty, modu艂y, zakresy (ranges), korutyny. |
Matematyczne Aspekty J臋zyk贸w
Typy Danych i Arytmetyka
Oba j臋zyki oferuj膮 podstawowe typy danych, takie jak int
, float
, double
, char
. Jednak C++ wprowadza dodatkowe typy, np. bool
(w C typ logiczny jest symulowany za pomoc膮 int
).
Arytmetyka w obu j臋zykach podlega tym samym regu艂om, ale C++ umo偶liwia przeci膮偶anie operator贸w, co pozwala na definiowanie w艂asnych typ贸w numerycznych z zachowaniem naturalnej sk艂adni.
Przyk艂ad przeci膮偶ania operator贸w dla liczb zespolonych:
class Zespolona {
private:
double re, im;
public:
Zespolona(double re = 0.0, double im = 0.0) : re(re), im(im) {}
Zespolona operator+(const Zespolona& z) const {
return Zespolona(re + z.re, im + z.im);
}
Zespolona operator*(const Zespolona& z) const {
return Zespolona(re * z.re - im * z.im, re * z.im + im * z.re);
}
};
Programowanie Generyczne i Koncepty
C++ umo偶liwia tworzenie algorytm贸w generycznych za pomoc膮 szablon贸w, co jest zbli偶one do parametr贸w typ贸w w matematyce. Wprowadzenie koncept贸w w C++20 pozwala na definiowanie wymaga艅 dla parametr贸w szablon贸w, co zwi臋ksza bezpiecze艅stwo i czytelno艣膰 kodu.
Przyk艂ad konceptu:
template<typename t="">
concept Liczba = requires(T a, T b) {
{ a + b } -> std::convertible_to<t>;
{ a - b } -> std::convertible_to<t>;
{ a * b } -> std::convertible_to<t>;
{ a / b } -> std::convertible_to<t>;
};
template<liczba t="">
T suma(T a, T b) {
return a + b;
}