如果你是.net程序员,不免会用到C++/C写的库。对于简单的调用,可以直接使用DllImport来完成就可以,详情可参考C#调用C/C++从零深入讲解。但是对于复杂的C++类和对象,尤其是类似于OCC的大型C++项目,DllImport可能不够方便,这就要引出C++/CLI方式来实现C#与C++/C库的交互。C++/CLI常用的5中场景有:
通常可经过 DllImport 属性包装出函数来调用
托管C++代码可以直接引用原有的头文件,直接调用非托管函数,而不需要声明。这样,既减少了工作量,又避免引入错误。缺点是,这种方法会增加一个DLL。要注意的是托管字符串和非托管字符串是有区别的,并需要转换(特别要注意的Unicode字符串和多字节字符串的转换)。
C++的源代码,实际上可以直接编译成托管代码
只要从#pragma unmanaged编译指示开始的程序,一率编译成非托管代码;要想恢复成托管代码,只要使用#pragma managed就可以了
不要DLL,直接把C++源代码与C#源代码一起编译成一个单独的Assembly
ref class Animal
{
public:
int legs;
void SetName(String^ name)
{
this->name = name;
}
String^ GetName()
{
return name;
}
private:
String^ name;
};
ref
关键字,该类就变成了托管类,是可以被gc来管理的。加上了ref的类被称为引用类型
,这是由于变量不实际包含对象,而是包含指向对象内存位置的指针,也可以称之为句柄
,引用对象必须分配在堆上。value
关键字来声明类,此时该类便是值类型,直接分配在栈上,变量本身包含对象本身。#include "pch.h"
using namespace System;
ref class AnimalRef
{
public:
int legs;
void SetName(String^ name)
{
this->name = name;
}
String^ GetName()
{
return name;
}
private:
String^ name;
};
value class AnimalValue
{
public:
int legs;
void SetName(String^ name)
{
this->name = name;
}
String^ GetName()
{
return name;
}
private:
String^ name;
};
int main(array<System::String^>^ args)
{
AnimalRef cat;
cat.SetName("mm");
cat.legs = 4;
Console::Write("cat:");
Console::WriteLine(cat.GetName());
AnimalValue dog;
dog.SetName("xx");
dog.legs = 4;
Console::Write("dog:");
Console::WriteLine(dog.GetName());
Console::WriteLine(sizeof(dog));
return 0;
}
类型 | 说明 |
---|---|
bool | |
char,__int8 | 单字节,一般用于容纳ASCII |
short,__int16 | 整数 |
int,__int32 | 整数 |
long | 整数,许多编译器中是int的两倍 |
long long ,__int64 | 整数 |
float | 浮点 |
double | 双精度 |
wchar_t | 宽字符或多字符 |
在标准C++中,基本数据类的大小是不固定的,如int可能是4字节,也可能是8,或者其他,这是根据运行平台来决定的,但是在c++/cli中基本数据类型的大小是固定的。
在标准C++中,指针容纳的是一个变量的内存地址,通过指针可以间接引用变量,但是C++/cli中,运行时会管理内存,所以它会将内存的东西一来一去以最大化的利用内容空间,这就意味着对象不会总在一个位置待着,这时候,指针的地址会过期。所以C++/CLI中没有指针的概念而是使用句柄
来包含变量的地址,运行时会自动更新这个地址。
声明句柄的方式就是在变量名前面加上^
符号,而且一般使用gcnew
操作符号来创建对象并获取它的句柄。
int main(array<System::String^>^ args)
{
AnimalValue^ cat = gcnew AnimalValue();
cat->legs = 4;
cat->SetName("mm");
Console::WriteLine(cat->GetName());
array<int>^ arr = gcnew array<int>(10);
arr[0] = 12;
Console::WriteLine(arr[0]);
return 0;
}
可以使用以下几种方式进行类型转换:
(float)7
尖括号中是目标类型
int a = 10;
double b;
b = static_cast<double>(a);