.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 在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的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),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
};