С++ const question

Если я это сделаю:

// 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

Ответ 1

Ключевое слово 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 передается по значению, константа не имеет значения.

Во втором примере вы говорите, что ваша функция принимает указатель на один тип, но затем реализует его как указатель на другой тип, поэтому он терпит неудачу.

Ответ 2

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

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

Следует также отметить, что между

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) {}

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

Ответ 3

См. этот вопрос, этот вопрос и this вопрос.

В принципе, константа означает, что функция не будет изменять значение указателя. Содержимое указателей не const, то же самое, что и подпись заголовка.

Ответ 4

В первом случае const не влияет на интерфейс, а только на реализацию. Вы говорите компилятору: "Я не собираюсь изменять значение bar* внутри этой функции". Вы все равно можете изменить то, на что указывает указатель. В последнем вы сообщаете компилятору (и всем вызывающим), что вы не измените структуру bar, на которую указывает bar*.

Ответ 5

Итак, вторая константа в:

void Foo::foo(const bar* const);

Является не частью сигнатуры метода?

Ответ 6

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

void foo( int i );

Определение может выглядеть так:

void foo( const int i ) { ... }

Является ли переменная "i" константой или нет на стороне определения, является деталью реализации. Это не влияет на клиентов этой функции.

Ответ 7

Вероятно, это не очень важно о void Foo::foo(bar* const pBar), потому что, как вы относитесь к самому указателю (const или нет), не имеет значения один бит вне процедуры. В правилах C говорится, что никакое изменение pBar не будет перемещаться за пределы foo в любом случае.

Однако, если это (const bar* pBar), это имеет значение, потому что это означает, что компилятор не должен позволять вызывающим абонентам передавать указатели на неконстантные объекты.