В нативном 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;
}
};
Теперь у клиента есть выбор: читать B-данные 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), постоянство потеряно.Действительно, следующее работает во второй сборке, ссылающейся на тот, который содержит класс A:
A ^a1 = gcnew A(1);
B ^b2 = a1->GetB();
b2->X = 2; // b->X changed within a1
Удивительно, но таким образом вы получаете «больший» доступ к объекту извне сборки, чем изнутри, потому что языковая конструкцияведет себя по-разному.Это предполагаемое поведение?
В любом случае, какова лучшая практика для преобразования идеи объекта с постоянным возвратом в мир .NET?Как бы вы реализовали класс A в стиле CLR, при условии, что класс B поддерживает огромное количество данных (слишком много для копирования), которые не следует изменять извне класса A?