|
Программирование >> Перегруженные имена функций и идентификаторы
class Base { public: virtual ~Base(); Виртуальный деструктор[20.4] ... class Derived : public Base { public: ~Derived(); ... private: Member x ; Derived::~Derived() Компилятор автоматически вызывает x .~Member() Компилятор автоматически вызывает Base::~Base() Примечание: в случае виртуального наследования порядок уничтожения классов сложнее. Если вы полагаетесь на порядок уничтожения классов в случае виртуального наследования, вам понадобится больше информации, чем изложено здесь. Расскажите все-таки о пресловутых нулевых указателях Для каждого типа указателей существует (согласно определению языка) особое значение - нулевой указатель , которое отлично от всех других значений и не указывает на какой-либо объект ии функцию. Таким образом, ни оператор &, ни успешный вызов malloc() никогда не приведут к появлению нулевого указателя. (malloc возвращает нулевой указатель, когда память выделить не удается, и это типичный пример использования нулевых указателей как особых величин, имеющих несколько иной смысл память не выделена или теперь ни на что не указываю .) Нулевой указатель принципиально отличается от неинициализированного указателя. Известно, что нулевой указатель не ссылается ни на какой объект; неинициализированный указатель может ссылаться на что угодно. В приведенном выше определении уже упоминалось, что существует нулевой указатель для каждого типа указателя, и внутренние значения нулевых указателей разных типов могут отличаться. Хотя программистам не обязательно знать внутренние значения, компилятору всегда необходима информация о типе указателя, чтобы различить нулевые указатели, когда это нужно. Как получить нулевой указатель в программе? В языке Си константа 0, когда она распознается как указатель, преобразуется компилятором в нулевой указатель. То есть, если во время инициализации, присваивания или сравнения с одной стороны стоит переменная или выражение, имеющее тип указателя, компилятор решает, что константа 0 с другой стороны должна превратиться в нулевой указатель и генерирует нулевой указатель нужного типа. Следовательно, следующий фрагмент абсолютно корректен: char *p = 0; if(p != 0) Однако, аргумент, передаваемый функции, не обязательно будет распознан как значение указателя, и компилятор может оказаться не способным распознать голый 0 как нулевой указатель. Например, системный вызов UNIX execl использует в качестве параметров переменное количество указателей на аргументы, завершаемое нулевым указателем. Чтобы получить нулевой указатель при вызове функции, обычно необходимо явное приведение типов, чтобы 0 воспринимался как нулевой указатель. execl( /bin/sh , sh , -c , ls , (char *)0); Если не делать преобразования (char *), компилятор не поймет, что необходимо передать нулевой указатель и вместо этого передаст число 0. (Заметьте, что многие руководства по UNIX неправильно объясняют этот пример.) Когда прототипы функций находятся в области видимости, передача аргументов идет в соответствии с прототипом и большинство приведений типов может быть опущено, так как прототип указывает компилятору, что необходим указатель определенного типа, давая возможность правильно преобразовать нули в указатели. Прототипы функций не могут, однако, обеспечить правильное преобразование типов в случае, когда функция имеет список аргументов переменной длины, так что для таких аргументов необходимы явные преобразования типов. Всегда безопаснее явные преобразования в нулевой указатель, чтобы не наткнуться на функцию с переменным числом аргументов или на функцию без прототипа, чтобы временно использовать не-ANSI компиляторы, чтобы продемонстрировать, что вы знаете, что делаете. (Кстати, самое простое правило для запоминания.) Что такое NULL и как он определен с помощью #define? Многим программистам не нравятся нули, беспорядочно разбросанные по программам. По этой причине макрос препроцессора NULL определен в <stdio.h> ии <stddef.h> как значение 0. Программист, который хочет явно различать 0 как целое и 0 как нулевой указатель может использовать NULL в тех местах, где необходим нулевой указатель. Это только стилистическое соглашение; препроцессор преобразует NULL опять в 0, который затем распознается компилятором в соответствующем контексте как нулевой указатель. В отдельных случаях при передаче параметров функции может все же потребоваться явное указание типа перед NULL (как и перед 0). Как #define должен определять NULL на машинах, использующих ненулевой двоичный код для внутреннего представления нулевого указателя? Программистам нет необходимости знать внутреннее представление(я) нулевых указателей, ведь об этом обычно заботится компилятор. Если машина использует ненулевой код для представления нулевых указателей, на совести компилятора генерировать этот код, когда программист обозначает нулевой указатель как 0 или NULL. Следовательно, определение NULL как 0 на машине, для которой нулевые указатели представляются ненулевыми значениями так же правомерно как и на любой другой, так как компилятор должен (и может) генерировать корректные значения нулевых указателей в ответ на 0, встретившийся в соответствующем контексте.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |