在本地C++中,将对象作为常量引用返回是很有意义的。考虑A类提供只读访问B类的一个实例:在C++/CLI中实现常量引用的最佳实践
class B {
public:
int X;
B(int x)
: X(x)
{}
B(const B &b) // copy constructor
: X(b.X)
{}
};
class A {
private:
B &b;
public:
A(int x)
: b(*new B(x))
{}
const B &GetB()
{
return b;
}
};
现在客户有选择读A的B-数据要么非常有效地被引用,或创建它,如果需要自己的副本:
A a1(1);
const B &b1 = a1.GetB(); // constant reference
// b1.X = 2; // compilation error
B b2 = a1.GetB(); // through copy constructor
b2.X = 2; // ok, but doesn't affect a1
无论哪种情况,都可以保证外部没有人能够更改A的B成员实例中的数据。因此,这是一个完美的解决方案。
的等效CLI结构是这样的第一眼:
public ref class B {
public:
int X;
B(int x)
: X(x)
{}
};
public ref class A {
private:
B ^b;
public:
A(int x)
: b(gcnew B(x))
{}
const B %GetB()
{
return *b;
}
};
但这并不多大的意义,因为它工作在C++/CLI只。当你从一种不同的.NET语言引用它时,例如C#或VB.NET,你根本看不到GetB实现。好了,试试这个代替:
const B ^GetB()
{
return b;
}
托管指针是恒定的相同的组件内按预期:
A ^a1 = gcnew A(1);
const B ^b = a1->GetB(); // ok
b->X = 2; // error C3892: you cannot assign to a variable that is const
// error C2440: 'initializing' : cannot convert from 'const B ^' to 'B ^'
B ^b = a1->GetB();
在其他.NET组件的同时(使用C++/CLI即使),常数会丢失。事实上,第二assemply内的下列作品引用包含类A中的一个:
A ^a1 = gcnew A(1);
B ^b2 = a1->GetB();
b2->X = 2; // b->X changed within a1
出人意料的是,这样你有“更多”从组件比从内外部访问的对象,因为语言结构不同的行为。这是一种预期的行为吗?
无论如何,将常量返回对象的想法转化为.NET世界的最佳实践是什么?你如何实现CLR风格的类A,假如B类支持大量的数据(太多拷贝),而这些数据不应该从A类以外的地方改变?