.net 在C+中实现常量引用的最佳实践+/CLI 在本地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数据,或者根据需要创建自己的副本:.net 在C+中实现常量引用的最佳实践+/CLI 在本地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; } };,.net,reference,c++-cli,constants,language-design,.net,Reference,C++ Cli,Constants,Language Design,现在,客户可以选择通过引用非常高效地读取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 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),constance也会丢失。实际上,以下内容在第二个集合中起作用,该集合引用了包含类a的集合:
A ^a1 = gcnew A(1);
B ^b2 = a1->GetB();
b2->X = 2; // b->X changed within a1
令人惊讶的是,通过这种方式,您可以从程序集外部“更多”访问对象,而不是从内部,因为语言构造的行为不同。这是故意的行为吗
无论如何,将常量返回对象的概念转化为.NET世界的最佳实践是什么?如果类B支持大量不应从类A外部更改的数据(太多无法复制),您将如何以CLR样式实现类A?.NET不幸的是,它没有常量正确性的概念。C++/CLI编译器可以很好地处理本机类型上的
const
,但使其无法用于托管类型
为这个坏消息感到抱歉。我和你一样讨厌它。如果你想要在.NET中感觉像常量的东西,那么你必须使用不可能改变对象并传递这些接口的东西来创建接口。它不像常量那么方便,但外部效果是一样的 顺便说一句。。。你的例子很奇怪。第一个B有无意义的复制构造函数(因为它的行为类似于编译器生成的构造函数),所以它可能应该是:
class B
{
public:
int X;
B( int x )
: X( x )
{}
};
第一个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
};