2012-01-30 53 views
2

我想将本机C++库移植到C++/CLI,因此我可以在C#中使用它。我想弄清楚如何转换几个基本上轻轻包装提取字段的缓冲区的类。我已经写了一个小样本来更好地描述API中正在发生的事情。将本机缓冲区包装转换为C++/CLI

所以,我有一个Packet类,从文件中读取数据包:

#include <fstream> 
#include <cassert> 
#include "OptionalA.h" 

class Packet 
{ 
public: 
    Packet(void) 
    { 
     buffer = new char[PACKET_SIZE]; 
    } 
    ~Packet(void) 
    { 
     delete [] buffer; 
    } 

    void ReadNextPacket(std::ifstream& fileStream) 
    { 
     fileStream.read(buffer, PACKET_SIZE); 
    } 

    bool HasOptionalA() 
    { 
     return (buffer[0] & 0x1) == 1; 
    } 

    OptionalA GetOptionalA() 
    { 
     assert(HasOptionalA()); 
     return OptionalA(&buffer[1], &buffer[1] + OptionalA::OPTIONAL_A_SIZE); 
    } 

private: 
    const static int PACKET_SIZE = 3; 
    char* buffer; 
}; 

我创建的Packet有一个非常简单的格式:

[Packet: <Header Byte> [OptionalA: <Field1><Field2>]]

OptionalA类定义为如下:

#pragma once 
#include <cassert> 

class OptionalA 
{ 
public: 
    static const int OPTIONAL_A_SIZE = 2; 

    OptionalA(const char* begin = 0, const char* end = 0) : 
    begin(begin), end(end) 
    { 
     assert((end - begin) == OPTIONAL_A_SIZE); 
    } 

    char GetField1() 
    { 
     return begin[0]; 
    } 

    char GetField2() 
    { 
     return begin[1]; 
    } 

private: 
    const char* begin; 
    const char* end; 
}; 

什么是正确的方式来包装这种类的体系结构,以便我复制C++/CLI中的最小内存量?

回答

1

一个简单的方法,但耗费的时间稍长取决于你要转换类的量,是创建一个包含本地指针类型的CLI包装他们包装:

ref class FileStream 
{ 
public: 
    FileStream(String^ file) : 
    p(new std::ifstream()) 
    { 
    //open the stream here, if it fails throw a managed exception that makes sense 
    } 

    //bonus: CLI classes automatically implement IDisposable so 
    //this gets called at the end of scope with 'using(var x = new FileStream(){}' 
    ~FileStream() 
    { 
    delete p; 
    } 

    //make sure to implement a finalizer to make the GC work with this class 
    !FileStream() 
    { 
    this->~FileStream(); 
    } 

    //not repeating all functions here, we just use this as a placeholder 
    std::ifstream& Stream() 
    { 
    return *p; 
    } 

private: 
    std::ifstream* p; 
} 

ref class Packet 
{ 
public: 
    Packet() : 
    p(new native::Packet()) 
    { 
    } 

    //again destructor/finalizer pair 

    void ReadNextPacket(FileStream^ fileStream) 
    {     
    if(fileStream == nullptr) 
     throw gcnew System::ArgumentNullException("fileStream"); 
    p->ReadNextPacket(fileStream->Stream()); 
    }     

    bool HasOptionalA() 
    { 
    return p->HasOptionalA(); 
    } 

    OptionalA^ GetOptionalA() 
    { 
    retrun gcnew OptionalA(p->GetOptionalA()); 
    } 

private: 
    native::Packet* p; 
}; 

ref class OptionalA 
{ 
public: 
    OptionalA(const native::OptionalA& optionalA) : 
    p(new native::OptionalA(optionalA)) 
    { 
    } 

    //again destructor/finalizer pair 

    char GetField1()  
    {  
    return p=>GetField1(); 
    }  

private: 
    native::OptionalA* p; 
} 

香料的东西并做出更好的代码,考虑使用而不是原生本机指针并免费清理。也可以考虑使用std :: string并传递迭代器而不是原始字符指针,毕竟它是C++。

+0

我打算推荐我的智能指针,然后我看到你已经做到了。很好的选择!但是请注意,你的代码不能实现一个终结器,并且你的评论说析构函数被GC自动调用是错误的,如果没有明确的处理,它会泄漏。这是有点棘手得到正确的,所以使用智能指针;) – 2012-01-30 22:43:33

+0

此外,我假设你打算使'FileStream :: Stream'属性?语法错误。 – 2012-01-30 22:46:49

+0

@BenVoigt谢谢你指出这些问题,我从头开始编写所有东西,所以一定会犯一些错误:]解决它。 – stijn 2012-01-31 09:04:46

相关问题