Вопрос о языке программирования C ++ - PullRequest
4 голосов
/ 07 июня 2011

В главе 24.3.4 книги Язык программирования C ++ сказано, что

class Cfield : public Field{ /*...*/ }

Это выражает мнение, что Cfield на самом деле это своего рода поле, обеспечивает удобство записи, когда написание Cfield функции, которая использует член полевой части Cfield и - самое главное - позволяет Cfield переопределять поле виртуальные функции. Загвоздка в том, что преобразование Cfield* в Field* подразумевается в декларации Cfield побеждает все попытки контролировать доступ к Field:

void g(Cfield* p)
{
    *p = "asdf"; // access to Field controlled by Cfield's assignment operator:
                 // p->Cfield::operator=("asdf")

    Field* q = p; // implicit Cfield* to Field* conversion
    *q = "asdf"   // OOPS! no control
}

Чего я здесь не понимаю, так это жирного предложения. Как Cfield победил попытку контроля доступа к Field?

Собственно, последняя строка кода:

*q = "asdf"; 

вызовет Field::operator=("asdf"), так как же Cfield победил попытку контроля доступа к Field?

Ответы [ 3 ]

4 голосов
/ 07 июня 2011
Предполагается, что экземпляры

CField обеспечивают контролируемый (т.е. проверенный каким-либо образом CField::operator=()) доступ к данным базового класса Field.Но если вы неявно преобразуете CField * в Field *, то и затем разыменовываете его, этот контроль исчезает, потому что вы берете Field::operator=().

Я согласен, что это не самая ясная из работ Б.С.и мне кажется, что это не проблема - вы всегда можете получить «неконтролируемый доступ» к чему угодно, если только вы к этому подумаете.

2 голосов
/ 07 июня 2011

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

1 голос
/ 07 июня 2011

Давайте приведем конкретный пример:

struct Field {
  Field(char const* s): string(s) {}
  char const* string;
};

struct CField: Field {
  CField(char const* s): Field(s), length(s ? ::strlen(s) : 0) {}
  std::size_t length;
};

Это очень простой тип строки, который также не позволяет изменять строку, на которую он ссылается. CField увеличивает класс Field, кэшируя длину строки.

Сейчас в действии:

void foo(CField& cf) {  // 0
  cf = "foo";           // 1

  Field& f = cf;        // 2
  f = "foobar";         // 3
}

Что происходит?

  • строка 0: состояние неизвестно
  • строка 1: вызов CField& CField::operator=(CField const&), который создает временный CField (с использованием конструктора), cf.string равен "foo" и cf.length равен 3
  • строка 2: тот же объект, доступ через Field напрямую
  • строка 3: вызов Field& Field::operator=(Field const&), который создает временное Field (с использованием конструктора), cf.string равно "foobar" и cf.length равно 3 (без изменений)

Как вы можете заметить, инвариант, который length кэширует длину string, нарушен из-за незащищенного доступа к string через Field&.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...