从封装 VTK 到调用 WPF:C++/CLI 的强大用武之地
C++/CLI 简介与实战:桥接 C++ 与 .NET 的利器
概要:
这是一门神奇的语言 —— C++/CLI,也被称为“托管 C++”。它是微软专为 C++ 开发者设计的语言扩展,旨在让他们能够使用 .NET 平台的托管特性(如垃圾回收)。C++/CLI 只能通过 MSVC 编译器进行编译,其产出并非传统的可执行二进制文件,而是CLR(公共语言运行时)中的中间语言(IL)代码。
在生成的程序集里,托管部分可以被 CLR 加载并运行,而非托管部分则仍保留原生代码特性,被编译进程序集中供调用。
一些典型的应用场景包括(笔者实际使用的是第 3 种,即封装 VTK 库):
-
封装 Native C++ 库供 .NET 调用:相比 P/Invoke 或 COM 互操作,C++/CLI 提供了更高的灵活性和性能。
-
在 C++ 开发中调用 C# 的强大 UI 能力:无需额外封装,即可直接使用 WPF 或 WinForms。
-
作为 C++ 和 C# 的桥梁层:用于封装 OpenCV、FFmpeg 等 C++ 库,实现与 .NET 的高效交互。
C++/CLI 的语法特色
C++/CLI 是面向 C++ 开发者设计的,它在语法上保留了大量 C++ 特性,同时对 .NET 平台的诸如事件、属性、内存管理等机制提供了类 C++ 的接口。以下是参照官网一些常用特性和实践技巧:
1. 使用 Tracking References(% 符号)
C++/CLI 引入了 % 符号,类似于 C# 的 ref 关键字。例如:
void fun(int* p) {
p = new int[100];
}
以上代码修改的是参数副本,原指针不会变化。而使用:
void fun(int*& p) {
p = new int[100];
}
才能真正改变外部指针。C++/CLI 中,% 提供了类似语义:
void fun(int^% p) {
// 相当于 ref 传递引用
}
此外:
-
interior_ptr<T>:用于指向托管类型成员(如值类型或数组元素),允许指针操作同时支持 GC 移动。
-
pin_ptr<T>:用于将对象“钉住”,禁止 GC 移动,用于与 Native C++ 交互。
-
gcroot<T>:用于在原生 C++ 中持有托管对象引用。
2. 定义与使用类和结构体
C++/CLI 支持类似 C# 的方式定义 ref class(引用类)和 value struct(值类型),并支持:
-
访问控制(public/private/protected)
-
静态构造函数
-
析构函数(~ClassName)
-
终结器(!ClassName,相当于 Dispose)
注意:ref class 只能在托管堆上创建,而 value struct 可以栈上创建。
3. 栈语义支持(Stack Semantics for Reference Types)
为了模拟 C++ 的栈行为,C++/CLI 允许你为 ref class 定义栈语义(虽然对象实则仍创建在堆上,编译器会生成必要的拷贝/赋值逻辑),以实现更自然的 C++ 风格语义。
4. 用户自定义运算符(Operator Overloading)
C++/CLI 支持为以下运算符重载:
-
一元运算符:!、&、*、+、++、-、--、->、~、true、false
-
二元运算符:!=、%、&、&&、*、+、,、-、/、<、<<、<=、=、==、>、>=、>>、^、|、||
5. 自定义类型转换(User-Defined Conversions)
C++/CLI 提供了与标准 C++ 一致的机制,支持显式和隐式的类型转换运算符。
6. 委托的定义与使用(Delegates)
C++/CLI 支持类似 C# 的委托定义,可用于:
-
将托管委托传递给原生函数作为回调
-
使用 ref class 封装 native 函数,由委托调用
-
实现与原生代码的灵活交互
7. 事件机制(Events)
C++/CLI 中的事件支持自定义 add、remove 和 raise 方法,完全对标 C# 的事件模型。
8. 装箱(Boxing)
当值类型被赋给 System::Object 时,会触发装箱,即将其复制到托管堆上。触发装箱的典型情形包括:
-
将值类型赋值给 Object^
-
使用 gcnew 创建值类型实例
-
访问值类型时可使用 * 解引用以获取其内容
总结
C++/CLI 几乎支持了 C# 的所有关键特性,成为连接 C++ 与 .NET 世界的桥梁。你可以借助它在同一个项目中无缝使用 C++ 库和 .NET 库,实现高性能、高可维护性的混合开发。
当然,它也有一些坑需要注意:
-
拷贝构造函数调用的时机和次数
-
C# 和 C++ 字符编码之间的差异
-
C++/CLI 字符处理的陷阱
-
C# GC 释放时机不确定可能导致的对象失效
-
C++ 与 .NET 库命名冲突的问题
总体而言,掌握 C++/CLI 不仅可以提升跨语言开发效率,也能更深入理解内存模型、垃圾回收、编码机制等底层概念,是一门非常值得探索的技术。

浙公网安备 33010602011771号