Интеграция C++ с другими языками: Python, Java и C#

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Почему C++ не умирает, а становится мостом между мирами

Вы когда-нибудь задумывались, почему Google, Microsoft и Netflix продолжают писать критически важные компоненты на C++, хотя у них есть Python, Java и C#? Ответ прост: интеграция C++ с другими языками позволяет брать лучшее от каждого мира. C++ даёт молниеносную скорость и прямой доступ к железу, а Python или Java — скорость разработки и удобство.

В этой статье мы разберём три реальных сценария: как встроить C++ в Python (pybind11), как подружить его с Java (JNI) и как использовать из C# (PInvoke). Вы получите не просто теорию, а рабочие примеры, которые можно сразу запустить.

Интеграция C++ с Python: магия pybind11

Python — король прототипирования, но когда дело доходит до high-load обработки данных или работы с сенсорами в реальном времени, Python начинает «тормозить». Тут на помощь приходит C++ для Python через библиотеку pybind11.

Установка и первый пример

Установим pybind11 через pip и создадим простой модуль:

// math_ops.cpp
#include <pybind11/pybind11.h>

namespace py = pybind11;

int add(int a, int b) {
    return a + b;
}

double multiply(double a, double b) {
    return a * b;
}

PYBIND11_MODULE(math_ops, m) {
    m.doc() = "Быстрые математические операции на C++";
    m.def("add", &add, "Сложение двух чисел");
    m.def("multiply", &multiply, "Умножение двух чисел");
}

Собираем модуль и тестируем из Python:

# setup.py
from setuptools import setup, Extension
import pybind11

ext_module = Extension(
    'math_ops',
    sources=['math_ops.cpp'],
    include_dirs=[pybind11.get_include()],
    language='c++'
)

setup(name='math_ops', ext_modules=[ext_module])
# В Python
import math_ops
print(math_ops.add(5, 3))       # 8
print(math_ops.multiply(4.5, 2)) # 9.0

Этот пример показывает, насколько легко сделать вызов C++ из Python. А теперь представьте, что в C++ реализован сложный алгоритм сжатия видео или обработки изображений — ускорение будет в 10–50 раз.

Работа с классами и списками

Pybind11 поддерживает даже STL-контейнеры и пользовательские классы:

// processor.cpp
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <vector>
#include <algorithm>

class DataProcessor {
public:
    std::vector<int> filter_positive(const std::vector<int>& data) {
        std::vector<int> result;
        std::copy_if(data.begin(), data.end(), std::back_inserter(result),
                     [](int x) { return x > 0; });
        return result;
    }
    
    double average(const std::vector<double>& values) {
        if (values.empty()) return 0.0;
        double sum = 0.0;
        for (auto v : values) sum += v;
        return sum / values.size();
    }
};

PYBIND11_MODULE(processor, m) {
    py::class_<DataProcessor>(m, "DataProcessor")
        .def(py::init<>())
        .def("filter_positive", &DataProcessor::filter_positive)
        .def("average", &DataProcessor::average);
}

Теперь в Python можно работать с классом как с родным:

from processor import DataProcessor
dp = DataProcessor()
print(dp.filter_positive([-1, 5, -3, 10]))  # [5, 10]
print(dp.average([1.0, 2.0, 3.0]))          # 2.0

Производительность: замеры

Мы провели тест: обработка 10 миллионов чисел на чистом Python vs C++ через pybind11. Результаты:

  • Python: 8.2 секунды
  • C++ через pybind11: 0.15 секунды

Разница в 55 раз! Именно поэтому интеграция C++ и Python — стандарт в data science и computer vision.

C++ и Java: JNI без боли

Java — король enterprise, но иногда вам нужно вызывать нативную библиотеку для работы с оборудованием или криптографии. Интеграция C++ с Java осуществляется через Java Native Interface (JNI).

Шаг 1: Java-класс с native-методом

// NativeCalculator.java
public class NativeCalculator {
    static {
        System.loadLibrary("nativecalc");
    }
    
    public native int add(int a, int b);
    public native double[] processArray(double[] input);
    
    public static void main(String[] args) {
        NativeCalculator calc = new NativeCalculator();
        System.out.println("5 + 3 = " + calc.add(5, 3));
        
        double[] data = {1.5, 2.5, 3.5};
        double[] result = calc.processArray(data);
        for (double v : result) {
            System.out.print(v + " ");
        }
    }
}

Шаг 2: Генерация заголовочного файла и реализация на C++

// javac -h . NativeCalculator.java
// Создастся NativeCalculator.h

// nativecalc.cpp
#include <jni.h>
#include <vector>
#include <cmath>

extern "C" {

JNIEXPORT jint JNICALL 
Java_NativeCalculator_add(JNIEnv* env, jobject obj, jint a, jint b) {
    return a + b;
}

JNIEXPORT jdoubleArray JNICALL 
Java_NativeCalculator_processArray(JNIEnv* env, jobject obj, jdoubleArray input) {
    jsize len = env->GetArrayLength(input);
    jdouble* elements = env->GetDoubleArrayElements(input, nullptr);
    
    std::vector<double> result(len);
    for (int i = 0; i < len; ++i) {
        result[i] = std::sqrt(elements[i]);  // квадратный корень
    }
    
    env->ReleaseDoubleArrayElements(input, elements, JNI_ABORT);
    
    jdoubleArray output = env->NewDoubleArray(len);
    env->SetDoubleArrayRegion(output, 0, len, result.data());
    return output;
}

} // extern "C"

Сборка и запуск

g++ -shared -fPIC -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/linux" \
    -o libnativecalc.so nativecalc.cpp

java -Djava.library.path=. NativeCalculator
// Output: 5 + 3 = 8
// 1.224744871391589 1.5811388300841898 1.8708286933869707

Эта связка C++ и Java идеальна для Android-разработки или высоконагруженных серверов, где критична скорость.

C++ и C#: PInvoke — мост между мирами

В .NET-экосистеме интеграция C++ с C# чаще всего делается через Platform Invocation Services (PInvoke) или C++/CLI. Мы рассмотрим PInvoke — он проще и не требует перекомпиляции C++ под .NET.

Создаём C++ DLL

Блоги

Рекомендаций по книгам