简体   繁体   中英

C++/CLI: return a reference to unmanaged object

I'm looking for a way to return the reference to another object that is a member of a managed object. This can be easily achieved in C++, but is a challenge for C++/CLI wrapper to be used with C#. Below is reproducible scenario (it's a lot of code, but it's all very easy, just demonstrating the problem)

C++ classes:

class NATIVEAPI NativeSlave
{
public:
    NativeSlave() : x_( 0 ), y_( 0.0 )
    {}

    NativeSlave( int x, double y ) : x_( x ), y_( y )
    {}

    int x_;
    double y_;
};

class NATIVEAPI NativeMaster
{
public:
    __declspec( property( get = getSlave, put = setSlave ) ) NativeSlave& slave;
    NativeSlave& getSlave()
    {
        return *pSlave; //returns a reference
    }
    void setSlave( const NativeSlave& slave )
    {
        *pSlave = slave;
    }

public:
    NativeMaster() : pSlave( new NativeSlave( 4, 5.0 ) )
    {}
    ~NativeMaster()
    {
        delete pSlave;
    }

private:
    NativeSlave* pSlave;
};

C++ usage:

NativeSlave slave = NativeSlave( 1, 2.0 ); //now, slave.x==1, slave.y==2.0
NativeMaster master; //now, master.slave.x==4, master.slave.y==5.0

master.slave = slave; //now, master.slave.x==1, master.slave.y==2.0
master.slave.x_ = 6; //now, master.slave.x==6
master.slave.y_ = 10.0; //now, master.slave.y==10.0

So in C++, we can easily get a reference to an underlying object and operate on its methods (here, members are public to simplify the example).

Then, the goal is to wrap this in C++/CLI to achieve the same functionality(usage) in C# as in C++ above:

C# (desired) :

ManagedSlave slave = new ManagedSlave(1, 2.0); //now, slave.x==1, slave.y==2.0
ManagedMaster master = new ManagedMaster(); //desired: master.slave.x==4, master.slave.y==5.0

master.slave = slave; //desired: master.slave.x==1, master.slave.y==2.0
master.slave.x = 6; //no appropriate get() method to change master.slave
master.slave.y = 10.0; //no appropriate get() method to change master.slave

Here is an attempt to write a wrapper:

C++/CLI ( with a problem in get/set property methods ):

public ref class ManagedSlave
{
public:
    property int x
    {
        int get()
        {
            return mSlave->x_;
        }
        void set( int x )
        {
            mSlave->x_ = x;
        }
    }
    property double y
    {
        double get()
        {
            return mSlave->y_;
        }
        void set( double y )
        {
            mSlave->y_ = y;
        }
    }
public:
    ManagedSlave( int x, double y ) : mSlave( new NativeSlave( x, y ) )
    {}
    ~ManagedSlave()
    {
        delete mSlave;
    }

internal:
    NativeSlave* mSlave;
};

public ref class ManagedMaster
{
public:
    property ManagedSlave^ slave
    {
        ManagedSlave^ get()
        {
            //??????????????????????????
        };
        void set( ManagedSlave^ slave )
        {
            //is this correct???????????
            mMaster->slave.x_ = slave->x;
            mMaster->slave.y_ = slave->y;
        };
    }

public:
    ManagedMaster() : mMaster( new NativeMaster() )
    {}
    ~ManagedMaster()
    {
        delete mMaster;
    }

internal:
    NativeMaster* mMaster;
};

.NET "references" are nothing like C++ references.

There is something in .NET that is the equivalent of a C++ reference, the ref keyword that qualifies arguments. But there's no way to use it for anything except arguments. (At the IL level it can be used for local variables also, but still not on return types)

Most of the time you can solve this by an extra layer of indirection.

In your particular case, it's really easy:

ManagedSlave( NativeSlave* s ) : mSlave( s )
{}
~ManagedSlave()
{
    // empty
}

ManagedSlave^ ManagedMaster::slave::get()
{
     return gcnew ManagedSlave( &mMaster->getSlave() );
}

// remove ManagedMaster::slave::set

Basically, there's no reason for ManagedSlave to be responsible for allocating and freeing a NativeSlave , because NativeMaster already does that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM