Если я сделаю это:
// In header
class Foo {
void foo(bar*);
};
// In cpp
void Foo::foo(bar* const pBar) {
//Stuff
}
Компилятор не жалуется, что подписи для Foo :: foo не совпадают. Однако если бы у меня было:
void foo(const bar*); //In header
void Foo::foo(bar*) {} //In cpp
Код не скомпилируется.
Что происходит? Я использую gcc 4.1.x
Вам следует выбрать ответ на свой вопрос или обновить, если это не тот ответ, который вы ищете.





Во-первых, вы обещали компилятору, но не другим пользователям класса, что вы не будете редактировать переменную.
Во втором примере вы обещали другим пользователям класса, что не будете редактировать их переменную, но не выполнили это обещание.
Следует также отметить, что между
bar* const variable
и
const bar* variable
и
const bar* const variable
В первой форме указатель никогда не изменится, но вы можете редактировать объект, на который он указывает. Во второй форме вы можете редактировать указатель (навести его на другой объект), но не переменную, на которую он указывает. В окончательной форме вы не будете редактировать ни указатель, ни объект, на который он указывает. Справка
Чтобы добавить немного больше пояснений к заданному вопросу, вы всегда можете пообещать БОЛЬШЕ const, чем меньше. Учитывая класс:
class Foo {
void func1 (int x);
void func2 (int *x);
}
Вы можете скомпилировать следующую реализацию:
Foo::func1(const int x) {}
Foo::func2(const int *x) {}
или же:
Foo::func1(const int x) {}
Foo::func2(const int* const x) {}
без проблем. Вы сказали своим пользователям, что можете редактировать их переменные. В своей реализации вы сказали компилятору, что эта конкретная реализация не будет редактировать эти переменные, даже если он сообщил пользователям, что вы можете. Вы не нарушили обещание, данное пользователю, поэтому код компилируется.
Я не думаю, что ваша теория верна: 1) Если вы объявляете «int *» и реализуете «const int *», как в вашем примере, он не компилируется. 2) Если вы передаете по значению, вы можете объявить const, а не реализовать с помощью const. Когда вы переходите по значению, это не имеет значения.
да. я согласен, вы ошибаетесь. void f (int const *); отличается от void f (int *); я думаю, вы хотели написать void f (int * const); имеет ту же сигнатуру, что и void f (int *); вам следует изменить свой пример, так как он может запутать новичков.
В первом случае const влияет не на интерфейс, а только на реализацию. Вы говорите компилятору: «Я не собираюсь изменять значение bar* в этой функции». Вы все еще можете изменить то, на что указывает указатель. В последнем случае вы сообщаете компилятору (и всем вызывающим абонентам), что вы не будете изменять структуру bar, которую представляет собой bar*указывает на.
Я думаю, вы имеете в виду в последнем предложении «вы не будете изменять полосу, на которую указывает полоса *». «Изменить то, на что указывает полоса *» может означать «присвоить полосе * новое значение», что, конечно, нормально во втором примере.
Спасибо за это, исправлено. Местоимения - проклятие ясности.
См. этот вопрос, этот вопрос и этот вопрос.
По сути, константа означает только то, что функция не будет изменять значение указателя. Содержимое указателей не является константным, как и подпись заголовка.
Итак, вторая константа в:
void Foo::foo(const bar* const);
Является ли нет частью сигнатуры метода?
Вы объявляете метод в файле .h, вы определяете его в .cpp. Все в объявлении является частью сигнатуры (обе константы), похоже, что в определении вы можете более точно уточнить тип аргумента, если это определение не нарушает семантику объявления.
@mamin: Верно. Например, посмотрите на ошибку компоновщика, которую вы получаете, если объявляете (но не определяете) функцию «void foo (const int * const a)», а затем вызываете ее. GCC сообщил об отсутствии подписи "foo (int const *)".
просто: если вы добавите / удалите const, он не будет частью подписи. так что void foo (intconst); и void foo (int); действительно имеют такую же подпись. НО void foo (int const *); и void foo (int *); имеют разные сигнатуры: к типу параметра добавляется не константа, а к указанному типу.
Ключевое слово const в первом примере бессмысленно. Вы говорите, что не планируете менять указатель. Однако указатель был передан по значению, поэтому не имеет значения, измените вы его или нет; это не повлияет на вызывающего абонента. Точно так же вы также можете сделать это:
// In header
class Foo {
void foo( int b );
};
// In cpp
void Foo::foo( const int b ) {
//Stuff
}
Вы даже можете сделать это:
// In header
class Foo {
void foo( const int b );
};
// In cpp
void Foo::foo( int b ) {
//Stuff
}
Поскольку int передается по значению, постоянство не имеет значения.
Во втором примере вы говорите, что ваша функция принимает указатель на один тип, но затем реализует ее как указатель на другой тип, поэтому она терпит неудачу.
Это проще понять с типом переменной, отличным от указателя. Например, у вас может быть следующее объявление функции:
void foo( int i );
Определение может выглядеть так:
void foo( const int i ) { ... }
Независимо от того, является ли переменная 'i' константой на стороне определения, является деталью реализации. Это не влияет на клиентов этой функции.
Я не понимаю, как голосуют пользователи SO. наверху проголосовало +15 выше, это ответ, в конце которого неверное утверждение, и он не хочет его исправлять (человек сказал ему это 3 месяца назад), а на -1 был этот ответ, который все в порядке и объяснен намного лучше (ИМХО). делаю +1 ради справедливости.
Вероятно, он не особо заботится о void Foo::foo(bar* const pBar), потому что то, как вы относитесь к самому указателю (константа или нет), не имеет значения вне подпрограммы. Правила C говорят, что никакие изменения в pBar в любом случае не будут выходить за пределы foo.
Однако, если это (const bar* pBar), это имеет значение, потому что это означает, что компилятор не разрешает вызывающим объектам передавать указатели на неконстантные объекты.
Вы хотели поместить константу с другой стороны от * во втором примере? Некоторые люди отвечают, объясняя разницу в значении этого, а другие отвечают, объясняя разницу в том, находится ли константа в файле cpp или h.