托管C++笔记,一原创

最近前一个项目结束,新的项目还未开始,并且下一个项目有可能需要用到C#/C++混合编程,于是乎开始了托管C++的学习过程。现在公司的游戏编辑器就是采用了C#做编辑器,C++做游戏引擎,托管C++做封装连接编辑器和引擎。不可否认.NET的功能强大,个人现在也偏好使用C#做工具。不过之前托管C++从未接触,想来凭借多年C++的底子和C#的经验,学习托管C++应该也不是件难事。

学习教材:Visual C++ .NET 托管扩展编程中文版,PDF扫描版,很不清晰………………勉强能看。

看完第一章,并经过动手试验以后发现书本上讲的很多东西已经过时了,我使用的环境是Visual Studio .NET 2005/2008,而教程应该是基于.NET 2003写的。

很多关键字已经在.NET 2005中更改过,具体更新列表可以参考mdsn或者点击这里

几个最基础的也是最重要的更新:

__gc class改成了ref class

__property 改成了 property

__abstract 改成了 abstract

__gc __interface 改成了 interface class

__event 改成了 event

不难看出来,这些改动只是把前面的下滑线去掉了。不过这只是字面上的改动

  • property的格式改成跟C#类似了

之前的格式是

__property void set_Name(String^ name);

__property String^ get_Name();

在2005里面变成了

property String^ Name

{

String^ get()

{

return mName;

}

void set(String^ name)

{

mName = name;

}

}

对于熟悉C#的人来说是一个非常不错的改进。

  • abstract改动让我很无语:

__abstract变成abstract以后,还必须放在类名字后面

原来的格式

__gc __abstract class Test : public Base

{

}

新的格式

ref class Test abstract : public Base

{

}

  • 空指针的判断

不再使用0或者null来判断指针是否为空了,而是用nullptr

  • new操作符的改动

因为托管类必须要在托管堆上分配,否则会引起错误。所以在旧版本里面要使用__gc new来创建实例,但是也允许直接new。这个有可能会造成误会。

新的版本里面,所有的托管类必须要用gcnew来创建实例,否则会产生编译错误

  • interface的实现必须使用virtual关键字

这跟旧版本有些区别,书上的范例:

__gc __interface IPrint

{

void Print();

__event OnPrinted* printed;

}

__delegate void OnPrinted(String*);

__gc class PrintedDoc : public IPrint

{

public:

void Print()

{

}

__event virtual OnPrinted* printed

}

旧版本只有成员才需要在实现的时候使用virtual,而方法没有要求。

但是在新版本里面必须要使用virtual,包括方法

下面是我做的一个测试

public interface class TestInterface

{

event CallMethod^ TestEvent;

property String^ Name

{

String^ get();

void set(String^ name);

}

void TestFunc();

}

ref class Test : public TestInterface

{

public:

virtual event CallMethod^ TestEvent;

property String^ Name

{

virtual void set(Strin^ name)

{

mName = name;

}

virtual String^ get()

{

return mName;

}

}

virtual void TestFunc()

{

}

protected:

String^ mName;

}

这里的interface class让我很困惑,为什么一定要加class,难道还可以用interface struct?

如果在实现类里面没有使用virtual,编译器会报错。另外补充一点,如果有派生类需要重写基类的虚方法,必须使用override,否则编译器报错

范例如下:

ref class Derived : public Test

{

public:

virtual void TestFunc() override

{

__super::TestFunc();

}

}

这里出现了__super关键字,跟C#的base和Java里面的super类似,通常在C++里面要调用基类的方法,我们都是采用Test::TestFunc()的形势,而且你也可以调用更上层的方法。而__super则限定了只能是直接基类的方法。

  • 奇妙的实现

.NET里面只允许单继承,也就是所有托管类只能有一个托管基类。

如果某个派生类实现了某个接口,但是没有提供实现方法,不过该派生类的基类有一个完全匹配实现,这个实现会被当成是接口的实现。

范例:

public interface class TestInterface

{

void TestFunc();

}

ref class TestFuncClass

{

public:

virtual void TestFunc()

{

}

}

ref class Test : public TestFuncClass, public TestInterface

{

}

上面的代码是可以编译通过的

  • 托管类可以delete

delete会调用该类的析构函数,但是该对象仍然存在于托管堆中,依然是有效的,只是析构里面可能更改了对象的状态,导致潜在的问题。

  • 托管C++里的event不需要判断是否为空指针

很神奇的发现这一点,在C#里面必须得检查这个event是否有人监听,否则直接触发这个事件会造成运行出错。

if (null != TestEvent)

{

TestEvent(....);

}

但是同样的代码放在托管C++里面反而会报编译错误。