风过无痕,生命如烟

每个人生下来都是天使,不过这个世界上也存在着恶魔。恶魔是天使变的,因为这个世界充满了诱惑。

导航

托管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++里面反而会报编译错误。

posted on 2010-10-21 12:03  hyamw  阅读(842)  评论(0编辑  收藏  举报