Почему классификатор const не работает с элементами-указателями на const-объектах? - PullRequest
7 голосов
/ 07 мая 2011

Я знаю, что об этом часто спрашивали, но единственные ответы, которые я мог найти, были, когда константность фактически была отброшена с использованием (int *) или подобного.Почему квалификатор const не работает с переменными-членами типа указателя на const-объектах, когда нет приведения?

#include <iostream>

class bar {
public:
    void doit()       { std::cout << "    bar::doit() non-const\n"; }
    void doit() const { std::cout << "    bar::doit() const\n"; }
};

class foo {
    bar* mybar1;
    bar mybar2;
public:
    foo() : mybar1(new bar) {}
    void doit() const {
        std::cout << "foo::doit() const\n";
        std::cout << "  calling mybar1->doit()\n";
        mybar1->doit();  // This calls bar::doit() instead of bar::doit() const
        std::cout << "  calling mybar2.doit()\n";
        mybar2.doit(); // This calls bar::doit() const correctly
    }
    // ... (proper copying elided for brevity)
};

int main(void)
{
    const foo foobar;  // NOTE: foobar is const
    foobar.doit();
}

Приведенный выше код дает следующий вывод (проверено в gcc 4.5.2 и vc100):

foo::doit() const
  calling mybar1->doit()
    bar::doit() non-const         <-- Why ?
  calling mybar2.doit()
    bar::doit() const

Ответы [ 3 ]

15 голосов
/ 07 мая 2011

Когда экземпляр foo является const, его элементы данных также являются константными, но это относится к указателям иначе, чем вы могли бы сначала подумать:

struct A {
  int *p;
};

A const obj;

Тип obj.p - int * const,не int const *;то есть постоянный указатель на int, а не указатель на константу int.

Чтобы взглянуть на него по-другому, давайте начнем с функции:

template<class T>
T const& const_(T const &x) {
  return x;
}

Теперь представьте, что у нас естьПример, и мы делаем его постоянным.Вы можете представить, что при применении const_ к каждому элементу данных.

A nc;
// nc.p has type int*.
typedef int *T;  // T is the type of nc.p.

T const &p_when_nc_is_const = const_(nc.p);
// "T const" is "int * const".

const T &be_wary_of_where_you_place_const = const_(nc.p);
// "const T" is "int * const".
// "const T" is *not* "const int *".

Переменная be_wary_of_where_you_place_const показывает, что «добавление const» равно , а не так же, как добавление «const» к буквальному текстутип.

1 голос
/ 07 мая 2011

Я собираюсь ответить на свой вопрос в этом случае.Ответ Фреда Нурка верен, но на самом деле не объясняет «почему».mybar1 и *mybar1 разные.Первый относится к фактическому указателю, а второй - к объекту.Указатель является константным (как предписано константой для foo; вы не можете сделать mybar1 = 0), но не указателем на объект, так как это потребует от меня объявить его const bar* mybar1.Объявление bar* mybar1 эквивалентно bar* const mybar1, когда объект foo является константным (то есть указатель является константным, а не указанным на объект).

0 голосов
/ 30 апреля 2014

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

Подробнее об этом можно прочитать в замечательной книге С. Мейерса "Эффективный с ++"

...