C++/CLI 是一种用于在 C++ 和 .NET 环境之间进行互操作的语言扩展,允许开发者使用 C++ 编写和操作托管代码(Managed Code)。以下是 C++/CLI 的语法大纲以及每部分的讲解。
C++/CLI 语法大纲
-
托管代码与非托管代码的定义
#pragma managed
/#pragma unmanaged
- 托管类型 (
ref class
,value class
,interface
)
-
托管类型
- 引用类型 (
ref class
,ref struct
) - 值类型 (
value class
,value struct
) - 枚举类型 (
enum class
,enum struct
)
- 引用类型 (
-
句柄与托管指针
- 托管指针
^
- 原生指针
*
- 托管指针
-
托管数组
- 使用
array<Type>
定义托管数组
- 使用
-
托管字符串
System::String
和String^
-
特性(Attributes)
- 属性标注(
[Attribute]
)
- 属性标注(
-
.NET 集合和泛型
List<T>
,Dictionary<TKey, TValue>
-
事件与委托
- 委托 (
delegate
) - 事件 (
event
)
- 委托 (
-
可见性
- 公共 (
public
) - 私有 (
private
) - 内部 (
internal
) - 保护 (
protected
)
- 公共 (
-
类型转换
safe_cast
,dynamic_cast
,static_cast
-
.NET 的托管内存管理
- 垃圾回收机制
gcnew
的使用
-
CLI 关键字
ref
,gcnew
,nullptr
,interface
,literal
,initonly
-
混合代码与互操作
- 混合模式编程
- P/Invoke 调用原生 DLL
- 从托管代码访问非托管代码
-
CLI 特有的语法
property
sealed
override
virtual
abstract
-
异常处理
try
/catch
捕获托管异常throw
抛出托管异常
语法详解
1. 托管代码与非托管代码
C++/CLI 支持两种代码模式:
- 托管代码:运行在 .NET 环境,由 CLR 管理。
- 非托管代码:传统的 C++ 原生代码。
切换托管/非托管代码
#pragma managed
void ManagedFunction() {
// 托管代码
}
#pragma unmanaged
void UnmanagedFunction() {
// 非托管代码
}
2. 托管类型
引用类型 (ref class
)
- 类似于 C# 的引用类型,分配在托管堆中。
ref class MyClass {
public:
int MyProperty;
};
值类型 (value class
)
- 类似于 C# 的值类型,分配在栈上或结构体中。
value class MyStruct {
public:
int X, Y;
};
接口 (interface
)
- 类似于 C# 的接口,定义方法约束。
interface class IMyInterface {
void MyMethod();
};
3. 句柄与托管指针
^
:托管对象的句柄。*
:原生指针。
示例
ref class ManagedClass {};
ManagedClass^ managedPtr = gcnew ManagedClass();
int* nativePtr = new int(10);
4. 托管数组
使用 array<T>
定义托管数组。
array<int>^ managedArray = gcnew array<int>(10);
managedArray[0] = 42;
5. 托管字符串
System::String
是 .NET 的字符串类型,通过 String^
使用。
String^ myString = "Hello, C++/CLI!";
Console::WriteLine(myString);
6. 特性(Attributes)
使用方括号标注属性。
[Serializable]
ref class MyClass {};
7. .NET 集合和泛型
C++/CLI 支持 .NET 泛型集合:
using namespace System::Collections::Generic;
List<int>^ myList = gcnew List<int>();
myList->Add(10);
8. 委托与事件
委托
delegate void MyDelegate(int value);
事件
ref class MyClass {
public:
event MyDelegate^ OnValueChanged;
};
9. 可见性
ref class MyClass {
private:
int privateField;
protected:
int protectedField;
public:
int publicField;
};
10. 类型转换
safe_cast
: 安全转换(类似于 C# 的as
)。dynamic_cast
: 用于托管和非托管之间的动态转换。static_cast
: 静态转换。
11. 托管内存管理
- 使用
gcnew
分配托管堆内存。
ManagedClass^ obj = gcnew ManagedClass();
12. CLI 关键字
ref
:定义引用类型。gcnew
:分配托管堆对象。nullptr
:托管对象的空值。literal
:常量定义。initonly
:只读字段。
13. 混合代码与互操作
调用非托管 DLL
[DllImport("user32.dll")]
extern "C" int MessageBox(IntPtr hWnd, String^ text, String^ caption, unsigned int type);
托管与非托管混合
void CallNativeFunction() {
#pragma unmanaged
// 原生 C++ 代码
#pragma managed
}
14. CLI 特有的语法
属性 (property
)
ref class MyClass {
private:
int value;
public:
property int Value {
int get() { return value; }
void set(int val) { value = val; }
}
};
sealed
ref class SealedClass sealed {};
override
virtual void MyMethod() override {}
abstract
virtual void MyAbstractMethod() abstract;
15. 异常处理
捕获和抛出托管异常:
try {
throw gcnew Exception("An error occurred!");
} catch (Exception^ ex) {
Console::WriteLine(ex->Message);
}
我们可以深入拓展和补充 C++/CLI 语法的应用场景和用法,以便更全面地掌握其功能和特性。
16. C++/CLI 与 C# 的对比
C++/CLI 提供了 .NET 的强大功能,同时保留了 C++ 的灵活性。以下是 C++/CLI 和 C# 之间的一些对比:
功能 | C++/CLI | C# |
---|---|---|
对象分配 | 使用 gcnew | 使用 new |
空值 | 使用 nullptr | 使用 null |
属性 | 使用 property | 直接定义 { get; set; } |
指针 | 支持托管指针 ^ 和原生指针 * | 仅支持托管对象 |
混合代码 | 支持托管和非托管代码切换 | 不支持 |
C++/CLI 示例:
ref class MyClass {
private:
int value;
public:
property int Value {
int get() { return value; }
void set(int val) { value = val; }
}
};
C# 示例:
public class MyClass {
public int Value { get; set; }
}
17. C++/CLI 混合模式
C++/CLI 是唯一支持托管代码和非托管代码混合的 .NET 语言。这是它最重要的功能之一。
定义与切换
通过 #pragma managed
和 #pragma unmanaged
,可以在托管和非托管代码之间切换。
#include <iostream>
#include <string>
void MixedFunction() {
#pragma unmanaged
std::string nativeStr = "Hello, Native!";
std::cout << nativeStr << std::endl;
#pragma managed
System::String^ managedStr = "Hello, Managed!";
System::Console::WriteLine(managedStr);
}
18. 类型互操作
C++/CLI 提供了从托管类型与非托管类型之间的高效转换机制。
托管类型与标准 C++ 类型的转换
- 使用
marshal_as
进行字符串转换:
#include <msclr/marshal_cppstd.h>
using namespace msclr::interop;
std::string ConvertToNative(String^ managedStr) {
return marshal_as<std::string>(managedStr);
}
String^ ConvertToManaged(const std::string& nativeStr) {
return marshal_as<String^>(nativeStr);
}
托管数组与原生数组的互操作
array<int>^ managedArray = gcnew array<int>(5);
int nativeArray[5];
for (int i = 0; i < 5; i++) {
nativeArray[i] = managedArray[i]; // 或反向赋值
}
19. CLI 特有关键字的详细解释
gcnew
- 用于在托管堆上分配对象。
- 示例:
MyClass^ obj = gcnew MyClass();
nullptr
- 等同于 .NET 的
null
,表示托管对象的空值。 - 示例:
MyClass^ obj = nullptr;
literal
- 定义编译时常量(类似于
const
,但仅适用于托管类型)。 - 示例:
literal int MaxValue = 100;
initonly
- 定义只读字段(只能在构造函数中赋值)。
- 示例:
ref class MyClass {
initonly int MaxValue;
public:
MyClass() : MaxValue(100) {}
};
20. 泛型编程
C++/CLI 支持 .NET 的泛型(Generic
),例如 List<T>
、Dictionary<TKey, TValue>
。
使用泛型集合
using namespace System::Collections::Generic;
List<int>^ intList = gcnew List<int>();
intList->Add(10);
intList->Add(20);
for each (int value in intList) {
Console::WriteLine(value);
}
21. 委托和事件的应用场景
委托
C++/CLI 的委托与 C# 的 delegate
类似,可用于回调机制。
delegate void MyDelegate(int value);
ref class MyClass {
public:
MyDelegate^ myDelegate;
void InvokeDelegate() {
myDelegate(42); // 调用委托
}
};
事件
C++/CLI 的事件使用 event
关键字,适合实现观察者模式。
ref class MyClass {
public:
event MyDelegate^ OnValueChanged;
void ChangeValue(int newValue) {
OnValueChanged(newValue); // 触发事件
}
};
22. 异常处理 捕获混合异常
C++/CLI 支持托管异常和非托管异常的处理。
捕获混合异常
try {
// 非托管代码
throw std::runtime_error("Native error!");
} catch (std::exception& ex) {
std::cerr << ex.what() << std::endl;
} catch (System::Exception^ ex) {
Console::WriteLine(ex->Message);
}
23. 从 C# 调用 C++/CLI
C++/CLI 可以作为一个桥梁,从 C# 调用非托管 C++ 代码。
示例:定义 C++/CLI 类
public ref class MyBridge {
public:
int Add(int a, int b) {
return a + b;
}
};
在 C# 中调用
var bridge = new MyBridge();
int result = bridge.Add(5, 10);
Console.WriteLine(result);
24. 应用场景
C++/CLI 主要适用于以下场景:
-
托管与非托管代码的桥梁:
- 用于将传统 C++ 库引入 .NET 项目。
-
性能优化:
- 在 .NET 应用中,使用 C++ 编写性能关键的组件。
-
与硬件交互:
- 在 .NET 环境中使用低级 C++ 库与硬件通信。
-
C++/CLI 替代 P/Invoke:
- 比 P/Invoke 更灵活和高效,用于调用非托管代码。
小结
C++/CLI 提供了与 .NET 完美互操作的能力,通过以上语法,开发者可以:
- 使用 C++ 编写和管理托管代码。
- 与 C# 或 VB.NET 的类库互操作。
- 在托管和非托管环境之间高效切换。