Давайте посмотрим на следующий код C ++:
#include <iostream>
int main()
{
int z = 2;
class A {
public:
const int & x;
A(const int & x) : x(x) {}
void show(){
std::cout << "x=" << this->x << std::endl ;
}
} a(z);
a.show();
z = 3;
a.show();
}
Программа печатает: 2 и 3
Это ясно показывает, что, хотя внутри класса A x нельзя изменить, это просто означает, что он только для чтения, потому что я могу изменить его значение извне.
Конечно, я могу сделать это копией, хранящейся в классе A, но мне интересно, есть ли (или есть ли предложение?) Способ сказать классу A, что член x будет действительно постоянным, а не просто прочитанным только со смыслом обещания, что внешний код не изменит его?
На мой взгляд это выглядит как нечто, связанное со значением C ограничивать Ключевое слово, но я еще не слышал о такой возможности C ++. Вы ?
Констанция является атрибутом фактической переменной.
Семестр const int& x
просто означает «x — это ссылка на int, которую он не изменит», и, конечно, компилятор обеспечивает это.
Если вы хотите, чтобы фактическая переменная, на которую ссылается x, была константой, просто объявите ее так:
#include <iostream>
int main()
{
const int z = 2; // declared const. Nothing may ever modify it
class A {
public:
const int & x;
A(const int & x) : x(x) {}
void show(){
std::cout << "x=" << this->x << std::endl ;
}
} a(z);
a.show();
z = 3; // this is a logic error, caught by the compiler.
a.show();
}
правильная компиляция выдает ошибку:
./const.cpp:41:7: error: read-only variable is not assignable
z = 3;
~ ^
1 error generated.
Вы ищете D’s immutable
Ключевое слово, которое было введено как новое понятие в этом языке именно потому, что, к сожалению, ответ — нет: его нет в C ++.
Constness в C ++ не означает неизменность, но то, что рассматриваемая переменная доступна только для чтения. Это может все еще быть изменено другими частями программы. Я понимаю ваш вопрос относительно того, возможно ли обеспечить истинную неизменность в вызываемой функции, не зная, что делает вызывающая сторона.
Конечно, вы можете создать класс-оболочку шаблона, который выполняет задачу:
template <typename T>
class Immutable
{
public:
template <typename ...Args>
Immutable( Args&&...args )
: x( std::forward<Args>(args)... )
{}
operator const T &() const
{
return x;
}
private:
const T x;
};
Пока ты не reinterpret_cast
или же const_cast
у вас будут действительно неизменные объекты, когда вы их оберните Immutable<T>
,
Однако, если у вас есть постоянная ссылка на некоторый объект, невозможно определить, имеет ли какая-либо другая часть программы непостоянный доступ к объекту. Фактически, базовый объект может быть глобальной или статической переменной, к которой у вас есть доступ только для чтения, но функции, которые вы вызываете, могут по-прежнему изменять его.
Это не может случиться с Immutable<T>
объект. Однако, используя Immutable<T>
может навязать вам дополнительную операцию копирования. Вы должны судить себя, можете ли вы жить с этим и оправдывает ли выгода прибыль.
Наличие функции требует const Immutable<Something> &
вместо const Something &
в качестве аргумента влияет на вызывающий код. Операция копирования может быть запущена. Кроме того, вы можете попросить Immutable<Something> &
без const
, Тогда никакие случайные копии не будут запущены, но вызывающий код должен передать ссылку на Immutable<Something>
объект. И это правильно, потому что, если абонент получил const &
в качестве аргумента вызывающая сторона не знает, может ли объект быть изменен кем-то еще в программе. Вызывающий объект должен создать сам объект или требовать, чтобы неизменный объект передавался ему в качестве ссылки.
Вот ваша оригинальная проблема с Immutable<int> &
вместо const int &
,
#include <iostream>
int main()
{
Immutable<int> z = 2;
class A {
public:
const Immutable<int> & x;
A(Immutable<int> & x) : x(x) {}
void show(){
std::cout << "x=" << this->x << std::endl ;
}
} a(z);
a.show();
//z = 3; // this would fail
a.show();
}
Вот как это работает: если вы пишете
void printAndIncrementAndPrint( int & i1, const int & i2 )
{
std::cout << i2 << std::endl;
++i1;
std::cout << i2 << std::endl;
}
int main()
{
int i = 0;
printAndIncrementAndPrint( i, i );
}
тогда он напечатает
0
1
в консоль. Если вы замените второй аргумент printAndIncrementAndPrint()
с const Immutable<int> & i2
и оставьте то же самое, тогда копия будет запущена, и она напечатает
0
0
на консоль. Вы не можете пройти и Immutable<int>
к функции и int &
к тем же базовым данным, не нарушая систему типов, используя const_cast
или же reinterpret_cast
,
Я думаю, что это проблема дизайна для программистов, а не язык. const
переменная означает для любого пользователя этой переменной, они не должны изменять значение этой переменной. Наш компилятор достаточно умен, чтобы помочь нам убедиться в этом. Так A
пользователь z
и если вы хотите A
знать, что A::x
ссылки на const
переменная, то вы должны сделать z
const int
, const reference
это просто сохранить договор между пользователем и провайдером.