在本机C ++中,将对象作为常量引用返回通常是有意义的。考虑A类提供对B类实例的只读访问:
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的A成员实例中的数据。因此,这是一个完美的解决方案。
乍一看,等效的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),constance也会丢失。实际上,下面的工作在第二部分中引用了包含A类的那个:
A ^a1 = gcnew A(1);
B ^b2 = a1->GetB();
b2->X = 2; // b->X changed within a1
令人惊讶的是,通过这种方式,您可以从程序集外部“更多”访问对象,而不是从内部访问,因为语言结构的行为方式不同。这是预期的行为吗?
无论如何,将常量返回对象的想法转换为.NET世界的最佳实践是什么?你如何实现CLR风格的A类,只要B类支持大量数据(复制太多),不应该从A类外部改变?
答案 0 :(得分:4)
const
,但是使托管类型无法使用它。
抱歉这个坏消息。我和你一样讨厌这个。
答案 1 :(得分:1)
如果你想在.NET中感觉像const,那么你必须使用不可能改变对象并传递这些接口来创建接口。它不像const那么方便,但外部效果是一样的。
顺便说一句......你的例子很奇怪。第一个B有无意义的复制构造函数(因为它的行为与编译器生成的一样),所以也许应该是:class B
{
public:
int X;
B( int x )
: X( x )
{}
};
First A正在泄漏它的b成员而getter不是const,所以也许应该是:
class A
{
private:
B b;
public:
A( int x )
: b( x )
{}
const B& GetB() const
{
return b;
}
private:
// block copy and assignment here
// if that was point of reference member
};