C++/CLI:return 对非托管对象的引用
C++/CLI: return a reference to unmanaged object
我正在寻找一种方法来 return 对作为托管对象成员的另一个对象的引用。这可以在 C++ 中轻松实现,但对于与 C# 一起使用的 C++/CLI 包装器来说是一个挑战。下面是可重现的场景(代码很多,但是都很简单,只是演示问题)
C++ 类:
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++ 用法:
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
所以在C++中,我们可以很容易的得到一个底层对象的引用,并对其方法进行操作(这里,为了简化例子,成员是public)。
然后,目标是将其包装在 C++/CLI 中,以在 C# 中实现与上述 C++ 中相同的功能(用法):
C# (期望):
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
这是编写包装器的尝试:
C++/CLI(get/set 属性 方法 中有问题):
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" 与 C++ 引用完全不同。
.NET 中有一些东西等同于 C++ 引用,即限定参数的 ref
关键字。但是除了参数之外,没有办法将它用于任何事情。 (在 IL 级别,它也可以用于局部变量,但仍然不能用于 return 类型)
大多数时候你可以通过一个额外的间接层来解决这个问题。
在您的特定情况下,这真的很简单:
ManagedSlave( NativeSlave* s ) : mSlave( s )
{}
~ManagedSlave()
{
// empty
}
ManagedSlave^ ManagedMaster::slave::get()
{
return gcnew ManagedSlave( &mMaster->getSlave() );
}
// remove ManagedMaster::slave::set
基本上,ManagedSlave
没有理由负责分配和释放 NativeSlave
,因为 NativeMaster
已经这样做了。
我正在寻找一种方法来 return 对作为托管对象成员的另一个对象的引用。这可以在 C++ 中轻松实现,但对于与 C# 一起使用的 C++/CLI 包装器来说是一个挑战。下面是可重现的场景(代码很多,但是都很简单,只是演示问题)
C++ 类:
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++ 用法:
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
所以在C++中,我们可以很容易的得到一个底层对象的引用,并对其方法进行操作(这里,为了简化例子,成员是public)。
然后,目标是将其包装在 C++/CLI 中,以在 C# 中实现与上述 C++ 中相同的功能(用法):
C# (期望):
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
这是编写包装器的尝试:
C++/CLI(get/set 属性 方法 中有问题):
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" 与 C++ 引用完全不同。
.NET 中有一些东西等同于 C++ 引用,即限定参数的 ref
关键字。但是除了参数之外,没有办法将它用于任何事情。 (在 IL 级别,它也可以用于局部变量,但仍然不能用于 return 类型)
大多数时候你可以通过一个额外的间接层来解决这个问题。
在您的特定情况下,这真的很简单:
ManagedSlave( NativeSlave* s ) : mSlave( s )
{}
~ManagedSlave()
{
// empty
}
ManagedSlave^ ManagedMaster::slave::get()
{
return gcnew ManagedSlave( &mMaster->getSlave() );
}
// remove ManagedMaster::slave::set
基本上,ManagedSlave
没有理由负责分配和释放 NativeSlave
,因为 NativeMaster
已经这样做了。