C++ — wieloparadygmatowy język programowania z ręcznym zarządzaniem pamięcią, łączący programowanie proceduralne, obiektowe i uogólnione. W programowaniu mobilnym C++ jest używany przez Android NDK do przenoszenia bibliotek oraz przez silniki gier Unity i Unreal Engine do tworzenia gier wieloplatformowych. Według TIOBE (2026), C++ znajduje się w pierwszej piątce najpopularniejszych języków wśród profesjonalnych programistów.
Najważniejsze
C++ — język programowania stworzony przez Bjarne Stroustrupa w 1985 roku jako rozszerzenie języka C o obsługę klas. C++ zapewnia bezpośredni dostęp do pamięci przez wskaźniki, metaprogramowanie szablonowe i dziedziczenie wielokrotne. Standardy C++17 i C++20 dodały korutyny, koncepty i ranges.
W przeciwieństwie do Javy i Kotlina, C++ nie ma garbage collectora — programista ręcznie zarządza alokacją i zwalnianiem pamięci przez operatory new i delete. Daje to pełną kontrolę nad wydajnością, ale wymaga dyscypliny. Według JetBrains Developer Survey (2025), 42% programistów C++ używa tego języka w branży gier.
Standardy C++ ewoluują co trzy lata: C++11 (lambdy, auto, unique_ptr), C++14 (lambdy uogólnione), C++17 (if constexpr, filesystem), C++20 (moduły, korutyny, koncepty). Kompilatory Clang i GCC obsługują wszystkie aktualne standardy, a dla Android NDK używany jest Clang z toolchaina LLVM.
Główna różnica C++ od języków JVM — ręczne zarządzanie pamięcią i kompilacja bezpośrednio do kodu maszynowego. Java i Kotlin działają na maszynie wirtualnej z automatycznym garbage collectorem. Kod C++ jest kompilowany do natywnego pliku binarnego dla konkretnej architektury — ARM, x86 lub RISC-V.
| Kryterium | C++ | Java / Kotlin |
|---|---|---|
| Zarządzanie pamięcią | Ręczne (new/delete, RAII) | Automatyczne (Garbage Collector) |
| Kompilacja | Natywny kod maszynowy | Kod bajtowy JVM / ART |
| Wydajność | Maksymalna (zero-cost abstractions) | Wysoka z pauzami GC |
| Zastosowanie w programowaniu mobilnym | NDK, gry, biblioteki | Aplikacje UI, logika biznesowa |
| Budowanie | CMake, NDK Build, Gradle + NDK | Gradle, Maven |
| Wieloplatformowość | Kompilacja dla każdej platformy | JVM / ART wszędzie |
Android NDK (Native Development Kit) — zestaw narzędzi Google do pisania części aplikacji Android w C i C++. NDK zawiera toolchain oparty na Clang, systemowe pliki nagłówkowe Androida, biblioteki do debugowania i profilowania. Wersja r27 (2025) obsługuje C++20 i używa LLVM 18.
NDK kompiluje kod C++ do bibliotek dynamicznych .so dla architektur ARM64, ARM32, x86 i x86_64. Aplikacja w Javie lub Kotlinie ładuje te biblioteki przez System.loadLibrary() i wywołuje funkcje native przez JNI. Według Google, NDK został pobrany ponad 5 milionów razy.
Typowy projekt z Android NDK zawiera folder app/src/main/cpp/ z plikami źródłowymi C++, CMakeLists.txt do budowania i klasę Java z deklaracją metod native. Gradle podłącza NDK przez blok externalNativeBuild w build.gradle.
// native-lib.cpp — prosty JNI-metoda dla Androida
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_app_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /*thiz*/) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}Kod deklaruje funkcję JNI z pełną nazwą Java_com_example_app_MainActivity_stringFromJNI — to konwencja nazewnictwa JNI. Funkcja przyjmuje wskaźnik na JNIEnv (środowisko wykonawcze) i jobject (instancję klasy wywołującej). env->NewStringUTF tworzy ciąg Java z ciągu C++.
Android obsługuje kilka ABI (Application Binary Interface): arm64-v8a (64-bitowe urządzenia ARM, 99% nowoczesnych smartfonów), armeabi-v7a (32-bitowe ARM, starsze urządzenia), x86_64 (emulatory). NDK umożliwia budowanie .so dla każdej architektury przez filtry ABI w build.gradle.
android {
defaultConfig {
ndk {
abiFilters "arm64-v8a", "armeabi-v7a"
}
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.22.1"
}
}
}C++ — główny język silników gier. Unreal Engine używa C++ dla całego kodu gry, a Unity wykorzystuje C++ w rdzeniu silnika do renderowania i fizyki. Nawet jeśli programista pisze w C# w Unity, pod maską C++ zarządza grafiką, dźwiękiem i obliczeniami fizycznymi.
Unreal Engine jest zbudowany na C++ od podstaw. Kod logiki gry pisze się w C++ z użyciem makr UHT (Unreal Header Tool) do integracji z Blueprints — wizualnym systemem skryptowania. Klasy dziedziczą po typach bazowych AActor, UObject, UGameInstance z literami prefiksowymi U, A, F.
// Klasa postaci w Unreal Engine w C++
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "MyCharacter.generated.h"
UCLASS()
class AMyCharacter : public ACharacter
{
GENERATED_BODY()
public:
AMyCharacter();
virtual void BeginPlay() override;
virtual void Tick(float DeltaTime) override;
UPROPERTY(EditAnywhere, Category = "Movement")
float MoveSpeed = 600.0f;
protected:
void SetupPlayerInputComponent(UInputComponent *PlayerInputComponent) override;
};Makra UCLASS() i UPROPERTY() — część systemu refleksji Unreal Engine. UHT (Unreal Header Tool) generuje kod C++ z plików nagłówkowych do serializacji, blueprintów i replikacji sieciowej. MoveSpeed jest wyświetlane w edytorze przez UPROPERTY(EditAnywhere).
Unity używa C# dla logiki gry, ale C++ jest stosowany w Native Plugins — bibliotekach .so dla Androida i .bundle dla iOS. Przez Android NDK można podłączać C++ SDK sieci reklamowych, analityki lub przenosić bibliotekę C++ z gier desktopowych.
using System.Runtime.InteropServices;
using UnityEngine;
public class NativeBridge : MonoBehaviour
{
const string LIB_NAME = "native_plugin";
[DllImport(LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
private static extern int ProcessFrame(
int width, int height,
IntPtr pixelData
);
void Update()
{
int result = ProcessFrame(Screen.width, Screen.height, IntPtr.Zero);
Debug.Log("Frame processed: " + result);
}
}W tym przykładzie C# marshaluje wywołanie funkcji C++ ProcessFrame przez P/Invoke. Atrybut DllImport wskazuje nazwę biblioteki .so. Funkcja C++ przetwarza klatkę w czasie rzeczywistym i zwraca wynik. Takie podejście stosuje się dla post-efektów i wizji komputerowej.
JNI (Java Native Interface) — standardowy mechanizm wywoływania kodu C/C++ z Javy lub Kotlina. W Androidzie JNI to jedyny sposób przesyłania danych między maszyną wirtualną ART a biblioteką natywną. Każde wywołanie JNI ma narzut, dlatego dane przesyła się pakietami, a nie pojedynczymi polami.
JNIEnv — wskaźnik na tablicę funkcji JNI. env->FindClass ładuje klasę Java, env->GetMethodID pobiera identyfikator metody, env->CallVoidMethod ją wywołuje. Dla ciągów używa się GetStringUTFChars i ReleaseStringUTFChars. JNI obsługuje również referencje globalne i słabe do obiektów Java.
// Przekazanie tablicy bajtów z C++ do Javy przez JNI
extern "C" JNIEXPORT void JNICALL
Java_com_example_app_ImageProcessor_processArray(
JNIEnv *env, jobject /*thiz*/,
jbyteArray input, jint length) {
jbyte *buffer = env->GetByteArrayElements(input, nullptr);
jsize size = env->GetArrayLength(input);
for (jsize i = 0; i < size; ++i) {
buffer[i] = buffer[i] ^ 0xFF; // odwracamy bajty
}
env->ReleaseByteArrayElements(input, buffer, JNI_COMMIT);
}GetByteArrayElements pobiera wskaźnik na tablicę bajtów Java. JNI_COMMIT w ReleaseByteArrayElements kopiuje zmiany z powrotem do tablicy Java bez zwalniania pamięci. Pętla for wykonuje przetwarzanie na CPU z maksymalną wydajnością C++ bez pauz GC.
Główne niebezpieczeństwo JNI — wycieki referencji globalnych. Każdy NewGlobalRef musi być zwolniony przez DeleteGlobalRef. Referencje lokalne (zwracane przez FindClass, NewStringUTF) są automatycznie usuwane przy powrocie z funkcji native. Do intensywnych wywołań używaj PushLocalFrame / PopLocalFrame.
CMake — główne narzędzie budowania dla C++ w Android NDK. CMakeLists.txt opisuje cele budowania, biblioteki i zależności. Gradle wywołuje CMake przez externalNativeBuild, przekazując ścieżki do NDK i toolchaina. Alternatywa — NDK Build oparty na Android.mk i Application.mk.
CMake 3.22+ obsługuje presety (CMakePresets.json) dla różnych konfiguracji: debug, release, profile z różnymi flagami optymalizacji. Dla Androida używany jest toolchain android.toolchain.cmake z NDK, automatycznie podstawiany przez Gradle podczas budowania.
# CMakeLists.txt dla projektu Android NDK
cmake_minimum_required(VERSION 3.22)
project("native-lib")
add_library(
native-lib
SHARED
src/main/cpp/native-lib.cpp
src/main/cpp/image_utils.cpp
)
target_include_directories(
native-lib PRIVATE
src/main/cpp/include
)
target_link_libraries(
native-lib
android
log
${CMAKE_SOURCE_DIR}/libs/libjpeg.a
)
set_target_properties(
native-lib PROPERTIES
CXX_STANDARD 20
CXX_STANDARD_REQUIRED ON
)add_library(SHARED) tworzy bibliotekę .so. target_link_libraries podłącza biblioteki systemowe android (dla JNI) i log (dla __android_log_print). Biblioteka statyczna libjpeg.a jest linkowana do pracy z obrazami JPEG. CXX_STANDARD 20 włącza obsługę C++20.
vcpkg — menedżer pakietów dla C++ od Microsoft, obsługujący Android NDK jako platformę docelową. Przez vcpkg można zainstalować Boost, OpenCV, SQLite, nlohmann-json i inne biblioteki skompilowane dla Android ABI. Vcpkg integruje się z CMake przez CMAKE_TOOLCHAIN_FILE.
C++ zapewnia maksymalną wydajność na urządzeniach mobilnych dzięki kompilacji do natywnego kodu ARM i brakowi garbage collectora. Według testów Google (Android Performance Patterns, 2024), kod JNI w C++ wykonuje się 3–10 razy szybciej niż równoważny kod Java dla zadań intensywnych obliczeniowo.
Kluczowe czynniki wydajności C++ na platformach mobilnych: lokalność pamięci podręcznej (umieszczanie danych w ciągłej pamięci), instrukcje SIMD NEON dla ARM, asynchroniczna praca z JNI przez kolejki komunikatów. NEON — rozszerzenie SIMD ARM, umożliwiające przetwarzanie 128 bitów danych w jednej instrukcji, niezbędne do przetwarzania audio, wideo i obrazów.
// Przetwarzanie tablicy SIMD przez NEON intrinsics
#include <arm_neon.h>
void process_audio_neon(float *data, size_t n) {
for (size_t i = 0; i < n; i += 4) {
float32x4_t vec = vld1q_f32(&data[i]);
float32x4_t result = vmulq_f32(vec, vdupq_n_f32(0.5f));
vst1q_f32(&data[i], result);
}
}vld1q_f32 ładuje 4 float z pamięci do 128-bitowego rejestru NEON. vmulq_f32 mnoży wszystkie 4 elementy przez 0.5 w jednym cyklu. vst1q_f32 zapisuje wynik z powrotem. Bez SIMD ta sama pętla wykonałaby 4 mnożenia sekwencyjnie — NEON daje przyspieszenie do 4x dla takich operacji.
| Operacja | C++ (ms) | Java/Kotlin (ms) | Przyspieszenie |
|---|---|---|---|
| Przetwarzanie obrazu 1920x1080 | 12 | 45 | 3.75x |
| Szybka transformacja Fouriera (FFT) | 8 | 34 | 4.25x |
| Szyfrowanie AES-256 bloku 1MB | 3 | 18 | 6x |
| Kompresja danych ZLIB | 5 | 22 | 4.4x |
Pierwszy i najniebezpieczniejszy błąd — wyciek pamięci. Każdy new musi mieć delete, każdy new[] — delete[]. Na urządzeniach mobilnych z ograniczonym RAM każdy wyciek prowadzi do OOM (Out Of Memory) i awarii aplikacji. Używaj RAII przez inteligentne wskaźniki: std::unique_ptr, std::shared_ptr, std::weak_ptr.
Drugi błąd — ignorowanie zgodności ABI. Biblioteka skompilowana dla armeabi-v7a nie załaduje się na urządzeniu ARM64. Zawsze określaj abiFilters w build.gradle i testuj na rzeczywistych urządzeniach, a nie tylko emulatorze x86_64. Używaj Android App Bundle do automatycznej filtracji ABI.
Trzeci typowy błąd — częste wywołania JNI. Każde przejście między Java a C++ kosztuje około 50–100 ns. Jeśli przetwarzasz tablicę 10000 elementów po jednym przez JNI, narzut przekroczy użyteczną pracę. Przekazuj dane całymi tablicami i przetwarzaj po stronie C++.
Problemy z wielowątkowością — kolejny częsty błąd. C++ może uruchamiać std::thread, ale dostęp do JNI jest możliwy tylko z wątku utworzonego przez Java. Do wywoływania metod Java z wątku C++ używaj AttachCurrentThread / DetachCurrentThread przez JNI.
// Prawidłowe wywołanie Java z wątku C++
JavaVM *g_vm; // globalny wskaźnik, uzyskany przy JNI_OnLoad
void background_task() {
JNIEnv *env;
jint res = g_vm->AttachCurrentThread(&env, nullptr);
if (res == JNI_OK) {
jclass clazz = env->FindClass("com/example/App");
jmethodID mid = env->GetStaticMethodID(clazz, "onProgress", "(I)V");
env->CallStaticVoidMethod(clazz, mid, 100);
g_vm->DetachCurrentThread();
}
}Często zadawane pytania
Android NDK (Native Development Kit) — zestaw narzędzi do pisania części aplikacji w C lub C++. Jest używany do zadań krytycznych dla wydajności, przenoszenia bibliotek C/C++ na Androida i implementacji kodu wieloplatformowego Unity i Unreal Engine.
W Unity kod logiki gry pisze się w C#, ale C++ jest używany w połączeniu z Android NDK do wtyczek, pracy z akceleracją sprzętową, przenoszenia własnych bibliotek C++ i integracji natywnych SDK dla reklam i analityki.
CMakeLists.txt opisuje pliki źródłowe, biblioteki i flagi kompilacji. Minimalna konfiguracja obejmuje add_library do budowania .so i target_link_libraries do podłączenia Android log i innych bibliotek systemowych.
JNI (Java Native Interface) to warstwa pośrednia między kodem Java/Kotlin aplikacji Android a biblioteką C++. Jeśli C++ jest wywoływany z Javy, JNI jest obowiązkowe. Można pisać kod C++ w całości przez NDK, ale punktem wejścia jest zwykle aktywność Java wywołująca funkcje native.
C++ jest uzasadniony dla gier, przetwarzania audio/wideo w czasie rzeczywistym, wizji komputerowej, kryptografii, symulacji fizycznych i przenoszenia bibliotek z innych platform. Do zwykłej aplikacji UI Kotlin jest wydajniejszy i prostszy.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również