C++ — 一种多范式编程语言,具有手动内存管理功能,结合了过程式、面向对象和泛型编程。在移动开发中,C++通过Android NDK用于移植库,并通过Unity和Unreal Engine游戏引擎用于创建跨平台游戏。根据TIOBE(2026年),C++在专业开发人员中的受欢迎程度位居前五名。
要点
C++ — 由Bjarne Stroustrup于1985年创建的编程语言,作为C语言的扩展,增加了对类的支持。C++通过指针提供直接内存访问、模板元编程和多继承。C++17和C++20标准添加了协程、概念和范围。
与Java和Kotlin不同,C++没有垃圾回收器——开发人员通过new和delete运算符手动管理内存的分配和释放。这提供了对性能的完全控制,但需要自律。根据JetBrains Developer Survey(2025),42%的C++开发人员在游戏行业使用该语言。
C++标准每三年进化一次:C++11(lambda、auto、unique_ptr)、C++14(泛型lambda)、C++17(if constexpr、filesystem)、C++20(模块、协程、概念)。Clang和GCC编译器支持所有当前标准,而Android NDK使用LLVM工具链中的Clang。
C++与JVM语言的主要区别——手动内存管理和直接编译为机器码。Java和Kotlin在带有自动垃圾回收器的虚拟机上运行。C++代码被编译为针对特定架构(ARM、x86或RISC-V)的原生二进制文件。
| 标准 | C++ | Java / Kotlin |
|---|---|---|
| 内存管理 | 手动(new/delete, RAII) | 自动(Garbage Collector) |
| 编译 | 原生机器码 | JVM / ART 字节码 |
| 性能 | 最大(零成本抽象) | 高,有GC暂停 |
| 在移动开发中的使用 | NDK、游戏、库 | UI应用、业务逻辑 |
| 构建 | CMake、NDK Build、Gradle + NDK | Gradle、Maven |
| 跨平台性 | 为每个平台编译 | JVM / ART 无处不在 |
Android NDK(Native Development Kit) — Google的用于用C和C++编写Android应用程序部分的工具集。NDK包括基于Clang的工具链、Android系统头文件、用于调试和分析的库。r27(2025)版本支持C++20并使用LLVM 18。
NDK将C++代码编译为ARM64、ARM32、x86和x86_64架构的动态.so库。Java或Kotlin应用程序通过System.loadLibrary()加载这些库,并通过JNI调用原生函数。根据Google的数据,NDK已被下载超过500万次。
一个典型的Android NDK项目包含app/src/main/cpp/文件夹(包含C++源文件)、用于构建的CMakeLists.txt和声明原生方法的Java类。Gradle通过build.gradle中的externalNativeBuild块连接NDK。
// native-lib.cpp — 一个简单的Android JNI方法
#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());
}代码声明了一个全名为Java_com_example_app_MainActivity_stringFromJNI的JNI函数——这是JNI命名约定。该函数接收一个指向JNIEnv(执行环境)的指针和jobject(调用类的实例)。env->NewStringUTF从C++字符串创建Java字符串。
Android支持多个ABI(Application Binary Interface):arm64-v8a(64位ARM设备,99%的现代智能手机)、armeabi-v7a(32位ARM,旧设备)、x86_64(模拟器)。NDK允许通过build.gradle中的ABI过滤器为每个架构构建.so。
android {
defaultConfig {
ndk {
abiFilters "arm64-v8a", "armeabi-v7a"
}
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.22.1"
}
}
}C++ — 游戏引擎的主要语言。Unreal Engine使用C++编写所有游戏代码,而Unity在引擎核心中使用C++进行渲染和物理计算。即使开发人员在Unity中用C#编写代码,幕后C++管理图形、声音和物理计算。
Unreal Engine从头开始基于C++构建。游戏逻辑代码使用UHT(Unreal Header Tool)宏编写,以便与Blueprints(可视化脚本系统)集成。类继承自基类型AActor、UObject、UGameInstance,带有前缀字母U、A、F。
// Unreal Engine中用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;
};UCLASS()和UPROPERTY()宏——Unreal Engine反射系统的一部分。UHT(Unreal Header Tool)从头文件生成C++代码,用于序列化、蓝图和网络复制。MoveSpeed通过UPROPERTY(EditAnywhere)在编辑器中显示。
Unity使用C#编写游戏逻辑,但C++用于Native Plugins——Android的.so库和iOS的.bundle库。通过Android NDK可以连接广告网络的C++ SDK、分析工具,或从桌面游戏移植C++库。
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);
}
}在此示例中,C#通过P/Invoke封送对C++函数ProcessFrame的调用。DllImport属性指定.so库的名称。C++函数实时处理帧并返回结果。这种方法用于后期效果和计算机视觉。
JNI(Java Native Interface) — 从Java或Kotlin调用C/C++代码的标准机制。在Android中,JNI是在ART虚拟机和原生库之间传输数据的唯一方式。每次JNI调用都有开销,因此数据以批处理方式传输,而不是逐个字段。
JNIEnv — 指向JNI函数表的指针。env->FindClass加载Java类,env->GetMethodID获取方法标识符,env->CallVoidMethod调用它。对于字符串,使用GetStringUTFChars和ReleaseStringUTFChars。JNI还支持对Java对象的全局和弱引用。
// 通过JNI将字节数组从C++传递到Java
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; // 反转字节
}
env->ReleaseByteArrayElements(input, buffer, JNI_COMMIT);
}GetByteArrayElements获取指向Java字节数组的指针。ReleaseByteArrayElements中的JNI_COMMIT将更改复制回Java数组而不释放内存。for循环处理在CPU上以最大C++性能执行,没有GC暂停。
JNI的主要危险——全局引用泄漏。每个NewGlobalRef必须通过DeleteGlobalRef释放。局部引用(由FindClass、NewStringUTF返回)在从原生函数返回时自动删除。对于密集型调用,请使用PushLocalFrame / PopLocalFrame。
CMake — Android NDK中C++的主要构建工具。CMakeLists.txt描述构建目标、库和依赖关系。Gradle通过externalNativeBuild调用CMake,传递NDK和工具链的路径。替代方案——基于Android.mk和Application.mk的NDK Build。
CMake 3.22+支持针对不同配置的预设(CMakePresets.json):debug、release、profile,使用不同的优化标志。对于Android,使用NDK中的android.toolchain.cmake工具链,由Gradle在构建时自动替换。
# Android NDK项目的CMakeLists.txt
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)创建一个.so库。target_link_libraries连接系统库android(用于JNI)和log(用于__android_log_print)。静态库libjpeg.a被链接用于处理JPEG图像。CXX_STANDARD 20启用C++20支持。
vcpkg — 微软的C++包管理器,支持Android NDK作为目标平台。通过vcpkg可以安装Boost、OpenCV、SQLite、nlohmann-json和其他为Android ABI编译的库。Vcpkg通过CMAKE_TOOLCHAIN_FILE与CMake集成。
C++由于编译为原生ARM代码且没有垃圾回收器,在移动设备上提供最大性能。根据Google的测试(Android Performance Patterns,2024),对于计算密集型任务,C++中的JNI代码执行速度比等效Java代码快3-10倍。
移动平台上C++性能的关键因素:缓存局部性(数据在连续内存中的放置)、用于ARM的NEON SIMD指令、通过消息队列与JNI异步工作。NEON — ARM的SIMD扩展,允许在一条指令中处理128位数据,对于音频、视频和图像处理不可或缺。
// 通过NEON intrinsics进行数组的SIMD处理
#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从内存加载4个float到128位NEON寄存器。vmulq_f32在一个周期内将所有4个元素乘以0.5。vst1q_f32将结果存回。没有SIMD,相同的循环将顺序执行4次乘法——NEON为此类操作提供高达4倍的加速。
| 操作 | C++(毫秒) | Java/Kotlin(毫秒) | 加速 |
|---|---|---|---|
| 处理1920x1080图像 | 12 | 45 | 3.75倍 |
| 快速傅里叶变换(FFT) | 8 | 34 | 4.25倍 |
| 加密AES-256 1MB块 | 3 | 18 | 6倍 |
| ZLIB数据压缩 | 5 | 22 | 4.4倍 |
第一个也是最危险的错误——内存泄漏。每个new必须有对应的delete,每个new[]必须有delete[]。在内存有限的移动设备上,任何泄漏都会导致OOM(Out Of Memory)和应用程序崩溃。通过智能指针使用RAII:std::unique_ptr、std::shared_ptr、std::weak_ptr。
第二个错误——忽略ABI兼容性。为armeabi-v7a编译的库无法在ARM64设备上加载。始终在build.gradle中指定abiFilters,并在真实设备上测试,而不仅仅是x86_64模拟器。使用Android App Bundle进行自动ABI过滤。
第三个常见错误——频繁的JNI调用。Java和C++之间的每次转换大约需要50-100纳秒。如果通过JNI逐个处理10000个元素的数组,开销将超过实际工作。将数据作为完整数组传递并在C++端处理。
多线程问题 — 另一个常见错误。C++可以启动std::thread,但只能从Java创建的线程访问JNI。要从C++线程调用Java方法,请通过JNI使用AttachCurrentThread / DetachCurrentThread。
// 从C++线程正确调用Java
JavaVM *g_vm; // 在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();
}
}常见问题
Android NDK(Native Development Kit) — 用于用C或C++编写应用程序部分的工具集。它用于对性能关键的任务、将C/C++库移植到Android以及实现Unity和Unreal Engine的跨平台代码。
在Unity中,游戏逻辑代码用C#编写,但C++与Android NDK结合用于插件、处理硬件加速、移植专有C++库以及集成用于广告和分析的原生SDK。
CMakeLists.txt描述源文件、库和编译标志。最小配置包括用于构建.so的add_library和用于连接Android log和其他系统库的target_link_libraries。
JNI(Java Native Interface) — Android应用程序的Java/Kotlin代码和C++库之间的中间层。如果从Java调用C++,则JNI是必需的。可以完全通过NDK编写C++代码,但入口点通常是调用原生函数的Java Activity。
C++适用于游戏、实时音频/视频处理、计算机视觉、密码学、物理模拟以及从其他平台移植库。对于普通的UI应用程序,Kotlin更高效、更简单。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。