2010-10-08 3 views
26

Прошу прощения, если это было задано, но как создать функцию-член в C++, которая возвращает указатель в следующих сценариях: 1. Возвращаемый указатель является постоянным, но его можно изменить. 2. Мусор внутри является постоянным, но возвращаемый указатель может быть изменен. 3. Ни мусор, ни указатель не могут быть изменены.Функция const const const, возвращающая указатель const. Но какой тип const является возвращаемым указателем?

Является ли это так:

  1. int *const func() const
  2. const int* func() const
  3. const int * const func() const

Все учебники, которые я читал, не покрывают это различие.

Замечание: Если мой метод объявлен как const, в учебниках сказано, что я не буду изменять параметры. Но это недостаточно ясно для меня в том случае, когда параметр является указателем , Должны ли мои параметры быть похожими:

a. void func(const int* const x) const;
b. void func(const int* x) const;
c. void func(const int* const x) const;

+0

понял, что константный funcs членов не имеет ничего общего с модифицирующими параметрами, но об изменении переменного класса. – Jor

ответ

53

Я не знаю, что книга, которую вы прочитали, но если вы отмечаете метод сопзЬ это означает, что this будет типа const MyClass* вместо MyClass*, что в свою очередь означает, что вы не можете изменить нестатические элементы данных, не объявлено mutable, и вы не можете вызвать любые неконстантные методы на this.

Теперь для возвращаемого значения.

1. int * const func() const

Функция постоянна, а возвращаемый указатель постоянный, но «мусор внутри» может быть изменен. Тем не менее, я не вижу смысла возвращать константный указатель, потому что конечный вызов функции будет rvalue, а значения типа non-class не могут быть const, что означает, что const будет проигнорировано в любом случае

2. const int* func() const

Это полезная вещь. «Утиль внутри» не может быть изменена

3. const int * const func() const

семантически почти так же, как 2, по причинам в 1.

HTH

+1

Я думаю, что у вас есть пара полезных сведений в этом ответе, но мой вопрос по-прежнему остается. Если я создаю метод member const, то, что я * обязательно * должен иметь в качестве моей сигнатуры метода. Прошу прощения, если я не понимаю вас. – Jor

+1

@ Jor: Вы не обязаны запрашивать какие-либо ограничения для остальной части сигнатуры функции. Единственное, что нужно отметить, это то, что в 'const' метод' this' является указателем на 'const', поэтому, если вы возвращаете элемент указателем или ссылкой, либо возвращаемое значение должно быть ссылкой или указателем на тип' const' или вам нужно будет сделать потенциально опасный 'const_cast'. –

+1

@Jor: То есть тип возврата зависит от того, что вы возвращаете. Если вы возвращаете адрес члена класса, то этот член является const внутри функции-члена const, поэтому вам нужно выбрать параметр (2). –

9

Некоторые виды использования сопзЬ на самом деле не имеет особого смысла.

Предположим, у вас есть следующие функции:

void myFunction (const int value); 

Конст говорит компилятору, что значение не должно измениться внутри функции. Эта информация не имеет значения для вызывающего абонента.Это зависит от самой функции, чтобы решить, что делать со значением. Для абонентов, следующие два определения функции ведут себя точно так же для него:

void myFunction (const int value); 
void myFunction (int value); 

Поскольку значение передается по значению, это означает, что функция получает локальную копию в любом случае.

С другой стороны, если аргумент является ссылкой или указателем, все становится совсем по-другому.

void myFunction (const MyClass &value); 

Это говорит звонящему, что значение передается по ссылке (так за экраном на самом деле это указатель), но абонент обещает не изменять значение. То же самое верно и для указателей:

void myFunction (const MyClass *value); 

Проезжаем указатель на MyClass (из соображений производительности), но функция обещает не изменять значение.

Если бы написать следующее:

void myFunction (MyClass * const value); 

Тогда мы вернулись ИНТ он первый ситуации. myFunction получает указатель, который передается по значению, и который является константой. Поскольку MyFunction получает копию значения указателя, для вызывающего не имеет значения, является ли оно const или нет. Самое главное, что myFunction может изменять содержимое значения, потому что указательная переменная сама является константой, но содержимое в ней не является.

То же самое верно и для возвращаемых значений:

const double squareRoot(double d); 

Это не имеет никакого смысла. squareRoot возвращает double, но поскольку это передается по значению, и поэтому его нужно скопировать в мою локальную переменную, я могу делать все, что захочу.

С другой стороны:

const Customer *getCustomer(char *name); 

Сообщает мне, что GetCustomer возвращает меня указатель на клиента, и я не разрешается изменять содержимое клиента.

На самом деле, было бы лучше, чтобы сделать символьные-указатель-содержимое сопзЬ, а также, так как я не ожидаю, функция изменить данную строку:

const Customer *getCustomer(const char *name); 
+0

Хорошо, я начинаю понимать Патрика, и я понял, что метод const имеет отношение к тому, чтобы не изменять членов класса. Так что забудьте об этом. Но мне нравится ваш ответ, так что, возможно, вы можете ответить на эти вопросы: В «const Customer * getCustomer (char * name)»; вы сказали, что вызывающий абонент не может изменить результат. Но так ли это, что они не могут изменить результат через возвращаемую переменную, но если они скопируют этот указатель на другой указатель, они * могут * изменить содержимое? – Jor

+0

И вот еще вопрос. Метод const не может возвращать указатель на его члены класса, если это не указатель const. Но какой тип указателя const это должен быть? 1: const * int 2: const * const int 3: int * const – Jor

+0

Если вы присвойте возвращаемое значение функции const Customer * getCustomer() для переменной «Customer *», вы сможете изменить содержимое Клиента. Однако компилятор C++ дает ошибку в этом назначении, поскольку обычно вам не разрешено назначать const-указатель на неконстантный указатель, поскольку это предоставляет вам дополнительные права (а именно: возможность изменять содержимое Клиент). Однако в некоторых случаях (особенно при работе со старым чистым кодом C) вам может понадобиться обойти это, а затем вы должны использовать const_cast. – Patrick

0

Конст метод предотвращает вас от модификации участники. В случае указателей это означает, что вы не можете переназначить указатель. Вы можете изменить объект, на который указывает указатель на желание вашего сердца.

Поскольку указатель возвращается значением (копия), вызывающий не может использовать его для изменения элемента указателя класса. Следовательно, добавление const к возвращаемому значению ничего не добавляет.

Все будет по-другому, если вы хотите вернуть ссылку на указатель. Теперь, если указатель не был const, это означало бы, что функция, которая не имеет прав на изменение значения, предоставляет это право вызывающему.

Пример:

class X 
{ 
    int* p; 
public: 
    int* get_copy_of_pointer() const //the returned value is a copy of this->p 
    { 
     *p = 42; //this being const doesn't mean that you can't modify the pointee 
     //p = 0; //it means you can't modify the pointer's value 
     return p; 
    } 
    int* const& get_reference_to_pointer() const //can't return a reference to non-const pointer 
    { 
     return p; 
    } 
}; 
1

возвращающая указатель на константные делает много смысла, но возвращает константный указатель (вы не можете изменить), как правило, не добавляет никакой ценности (хотя некоторые говорят, что это может предотвратить ошибки пользователя или добавить компилятор оптимизация).

Это потому, что возвращаемое значение принадлежит вызывающей функции, то есть это их собственная копия, поэтому не имеет значения, изменяют ли они ее (указывая на что-то еще). Однако контент не «принадлежит» вызывающему абоненту, а разработчик функции может заключить контракт, что это информация только для чтения.

Функции члена-члена обязывают не изменять состояние класса, хотя это не обязательно выполняется в реальности компилятором. Я не имею в виду здесь const_cast или mutable members так же, как тот факт, что если ваш класс сам содержит указатели или ссылки, функция-член const превращает ваши указатели в постоянные указатели, но не делает их указателями на const, аналогично ваши ссылки не поворачиваются в ссылки-на-const. Если это компоненты вашего класса (и такие компоненты часто представлены указателями), ваши функции могут изменять свое состояние.

Могут использоваться члены Mutable, позволяющие вашему классу изменять их, не изменяя внутреннее состояние. Их обычно можно применять для:

  • Мьютексы, которые вы хотите заблокировать, даже для чтения.
  • Данные, которые являются ленивыми, т.е. заполняются при первом доступе.
  • Объекты, подсчитанные по ссылке: вы хотите увеличить счетчик ссылок, если у него есть другой просмотрщик, поэтому вы изменяете его состояние только для его чтения.

const_cast обычно считается «взломанным» и часто делается, когда кто-то еще не написал свой код правильно const-correct. Это может иметь значение, хотя в следующих ситуациях:

  • Несколько перегруженных где один является сопзЬ и один неконстантные и сопзЬ возвращает константную-ссылку и неконстантные возвращает неконстантную ссылку, но в остальном они одинаковые. Дублирование кода (если это не простой элемент данных get) не является отличной идеей, поэтому реализуйте одно с точки зрения другого и используйте const_cast, чтобы обойти компилятор.

  • Если вы хотите, в частности, вызвать перегрузку константы, но иметь неконстантную ссылку. Сначала запустите его в const.

4

int *const func() const

Вы не можете наблюдать const здесь несколько случаев

  • Взятие адреса func кроме.
  • В C++ 0x, непосредственно вызывающий func с синтаксисом функционального вызова в качестве операнда decltype, даст int * const.

Это потому, что вы возвращаете значение чистого указателя, то есть значение указателя, которое фактически не хранится в переменной указателя.Такие значения не являются константными, потому что они не могут быть изменены в любом случае. Вы не можете сказать obj.func() = NULL;, даже если забрать const. В обоих случаях выражение obj.func() имеет тип int* и не подлежит изменению (кто-то скоро укажет стандарт и придумает термин «rvalue»).

Так что в контексте вы используете возвращаемое значение, которое вы не сможете определить разницу. Только в случаях, когда вы ссылаетесь на декларацию или на целую функцию, вы заметите разницу.

const int* func() const

Это то, что вы обычно будете делать, если тело будет что-то вроде return &this->intmember;. Он не позволяет изменять значение int, делая *obj.func() = 42;.

const int * const func() const

Это просто сочетание первого два :)

Смежные вопросы