@zwh8800
2017-08-23T02:44:50.000000Z
字数 2310
阅读 191848
blog 归档 c++ .net
最近写一些小程序, 需要运行在 windows 下有个界面. 一开始是用 c# 搞, 可是 c# 读写二进制文件实在是太蛋疼了 (可能是我才疏学浅, C# 没学好, 有谁知道 C# 中怎么方便的把二进制文件中的首部直接读到一个结构体中?). 最后还是转向 c 艹大法. 用 c 艹又想方便的拖控件, 又不想带一大堆乱七八糟 dll, 又不想用 MFC. 也就只能试试蛋疼的 c++/cli 了.
下面大致记录一下, 比较乱。
c# 中有六大类型, 在 c++/cli 中对应的是这样:
| 类型 | c# | c++/cli |
|---|---|---|
| 值类型 | ||
| 结构 | struct | value class |
| 枚举 | enum | enum class |
| 引用类型 | ||
| 类 | class | ref class |
| 数组 | type[] | array<type> |
| 接口 | interface | interface class |
| 委托 | delegate | delegate |
在 c# 中声明一个变量时, 不需要指明变量是否为引用类型或值类型
在 c++/cli 中对于引用类型的声明需在类型后加帽子 ^(官方说法为跟踪句柄)
同时在使用变量的成员时, 对于引用类型和值类型应使用. 和 -> 来区分
如:
c#:
Form refInCSharp = new Form();Point valueInCSharp = new Point(1, 2);refInCSharp.Show();valueInCSharp.toString();
c++/cli
Form^ refInCli = gcnew Form();Point valueInCli = Point(1, 2);refInCli->Show();valueInCli.toString();
需要注意的是, 对于一个值类型调用基类函数 (既 Object 类的函数, 结构体只能继承于 Object), 会对值类型进行隐式装箱
在 c# 中实现一个~type() 析构函数时, 在底层实际实现的是一个 Finalize() 函数. 这个函数的调用时机不确定, 只有在 GC 主动收集的时候才会被调用 (对于实现了 Finalize() 函数的对象, 更是会被延迟回收, 因为会在第 0 代回收时被放入第 2 代, 这称之为不确定的终结化(non-deterministic finalization))
参见:https://msdn.microsoft.com/zh-cn/library/ee787088(v=vs.100).aspx
然而,不确定的终结化机制在对象维护一个关键的资源,例如一个数据库连接或者某种类型的锁的时候运转并不好。这种情况下我们需要尽快释放资源。
因此, c# 中提供了 IDispose 模式, 通过显式调用 Dispose() 函数来释放关键资源 (在 Dispose 函数中需调用 SuppressFinalize() 函数来禁止对象被放入第二代)
并且 c# 提供了 using 语法糖来协助调用 Dispose 函数:
下面两段 c# 代码是等价的
{Font font1 = new Font("Arial", 10.0f);try{byte charset = font1.GdiCharSet;}finally{if (font1 != null)((IDisposable)font1).Dispose();}}
using (Font font1 = new Font("Arial", 10.0f)){byte charset = font1.GdiCharSet;}
可见, 在 c# 中使用 using 语句可以避免显式的调用 Dispose 函数.
参见:https://msdn.microsoft.com/zh-cn/library/yh598w02.aspx
在 c++/cli 中, 这变得更加简单:
首先, 和 c# 不同的是, 在 c++/cli 中实现一个~type 析构函数在底层实际上生成的是 Dispose 函数
如:
ref class A{public:virtual ~A(){System::GC::SuppressFinalize(this);A::Finalize();}};
等价于下面:
__gc class A : IDisposable{public:void Dispose(){System::GC::SuppressFinalize(this);Console::WriteLine( "in ~A"); }}};
而在 c++/cli 中如果需要使用想 using 那样的语法糖, 只需要把引用类型的帽子去掉即可:
void f(){Font font("Arial", 10.0f);Byte charset = font.GdiCharSet;// ...// font 被自动析构 -// 也就是说, font.Dispose() 被调用...}
等价于:
void f(){Font^ font = gcnew Font("Arial", 10.0f); /* 注意gcnew */Byte charset = font->GdiCharSet; /* 注意把点改为-> *///......delete font; /* 显式删除调用Dispose */}
这点设计简直 32 个赞!
另外, 去掉帽子并不代表 Font 对象被分配到栈上, 上面两段代码是完全等价的, 也就是说, font 还是会被 gcnew 到托管堆上. 这种使用方法只是一种语法糖而已.
另外, 真的想为一个类实现一个 Finalize 函数怎么办?
使用!type 的格式 (叹号 + 类名):
public ref class R {public:!R(){ Console::WriteLine( "I am the R::finalizer()!" ); }};
等价于:
public ref class R {public:void Finalize(){ Console::WriteLine( "I am the R::finalizer()!" ); }};
暂时就先这么多.
