C ++ постоянный вопрос - PullRequest
       95

C ++ постоянный вопрос

8 голосов
/ 06 ноября 2008

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

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

Ответы [ 7 ]

15 голосов
/ 06 ноября 2008

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

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

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

есть четкая разница
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) {}

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

6 голосов
/ 06 ноября 2008

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

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

1 голос
/ 06 ноября 2008

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

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

0 голосов
/ 06 ноября 2008

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

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

0 голосов
/ 06 ноября 2008

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

void foo( int i );

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

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

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

0 голосов
/ 06 ноября 2008

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

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

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

0 голосов
/ 06 ноября 2008

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

...