You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建可与Swift互操作且含析构函数的C++类?

问题:带析构函数的C++类与Swift互操作失败

问题场景

需要创建一个可与Swift互操作且带有析构函数的C++类,示例代码如下:

C++代码

namespace Name {
    class Foo
    {
    public:
        Foo() = default;
        Foo(uint32_t i); // 实现放在.cpp文件中
        ~Foo(); // 实现放在.cpp文件中
    };
}

Swift代码

import cxxLib
let bar = Name.Foo(2)

遇到的错误

编译时触发如下错误:

main.swift: error: 'Foo' is unavailable: non-trivial C++ class with trivial ABI is not yet available in Swift
let bar = Name.Foo(2)
               ^~~
__ObjC.cv:3:19: note: 'Foo' has been explicitly marked unavailable here
    public struct Foo {
                  ^

移除析构函数后代码可正常运行,但C标准库中的类(必然带析构函数)通过创建模板类型别名即可在Swift中使用,因此需要找到实现自定义带析构函数C类与Swift互操作的方案。环境:Windows系统,Swift 5.10。


解决方案

方法1:使用PIMPL(指针实现)模式包装类

通过将类的核心逻辑隐藏在内部实现类中,对外暴露的类仅持有指针,让其ABI变为平凡类型,同时保留析构函数的资源清理能力:

修改后的C++代码

namespace Name {
    // 前置声明内部实现类
    class FooImpl;

    class Foo
    {
    public:
        Foo() = default;
        explicit Foo(uint32_t i);
        ~Foo(); // 析构函数用于销毁内部Impl指针

        // 禁用拷贝(如需支持可手动实现)
        Foo(const Foo&) = delete;
        Foo& operator=(const Foo&) = delete;
        // 支持移动语义
        Foo(Foo&&) noexcept;
        Foo& operator=(Foo&&) noexcept;

    private:
        FooImpl* impl; // 指向实际实现的指针
    };
}

在.cpp文件中实现Foo的构造、析构和移动操作,内部FooImpl包含原有的业务逻辑和析构逻辑。这种方式下,对外的Foo类ABI平凡,Swift可正常访问,析构函数也能正确清理内部资源。

方法2:创建C风格包装接口

通过纯C函数封装C类的创建、销毁和操作,Swift直接调用C接口绕开对C类的直接限制:

C包装头文件(foo_wrapper.h)

#ifndef FOO_WRAPPER_H
#define FOO_WRAPPER_H

#include <stdint.h>

// 不透明指针,隐藏C++类细节
typedef struct Foo Foo;

// 创建Foo实例
Foo* Foo_Create(uint32_t i);
// 销毁Foo实例
void Foo_Destroy(Foo* foo);

#endif

C++实现文件(foo_wrapper.cpp)

#include "foo_wrapper.h"
#include "foo.h" // 包含原Foo类的头文件

struct Foo {
    Name::Foo inner; // 原C++类实例
};

Foo* Foo_Create(uint32_t i) {
    return new Foo{Name::Foo(i)};
}

void Foo_Destroy(Foo* foo) {
    delete foo;
}

Swift调用代码

import Foundation

// 导入C包装库
cImport {
    #include "foo_wrapper.h"
}

// 使用包装接口,defer确保资源释放
let bar = Foo_Create(2)
defer {
    Foo_Destroy(bar)
}

方法3:利用模板别名技巧

参考C++标准库的兼容方式,为自定义类创建模板类型别名,让Swift识别为可互操作类型:

C++头文件修改

namespace Name {
    class Foo
    {
    public:
        Foo() = default;
        Foo(uint32_t i);
        ~Foo();
    };

    // 创建模板别名
    template<typename T = void>
    using FooAlias = Foo;
}

Swift调用代码

import cxxLib
let bar = Name.FooAlias(2)

该技巧依赖Swift C++互操作的具体实现,可能存在版本兼容性差异,需结合当前Swift版本测试验证。


内容的提问来源于stack exchange,提问作者bquack-l

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 23:46:05