Программирование >>  Перегруженные имена функций и идентификаторы 

1 ... 157 158 159 [ 160 ] 161 162 163 ... 210


Тонкости и хитрости в вопросах и ответах

Я наследовал из абстрактного класса A класс B и определил все pure-методы. А она при выполнении ругается, что в конструкторе A по прежнему зовётся абстрактный метод? Почему и что делать?

Так и должно быть - в C++ конструкторы предков вызываются только до конструктора потомка, а вызов методов не инициализированного потомка может окончиться катастрофически (это верно и для деструкторов).

Поэтому и была ограничена виртуальность при прямом или косвенном обращении в конструкторе (деструкторе) предка к виртуальным методам таким образом, что всегда будут вызваны методы предка, даже если они переопределены в потомке.

Замечание: это достижимо подменой VMT.

Практически принятое ограничение поначалу сбивает с толку, а проблемы с TV (созданным в Турбо Паскале, где конструктор сам зовёт нужные методы и конструкторы предков) доказывают незавершённость схемы конструкторов C++, в котором из-за автоматического вызова конструкторов подобъектов (предков) сложно описать конструирование объекта как целого в одном месте, поэтому конструкторы C++ правильнее называть инициализаторами.

Таким образом, логичнее было бы иметь два шага: автоматический вызов инициализаторов предков (например, с обнулением указателей) и последующий автоматический же вызов общего конструктора. И в C++ это реализуемо!

Для этого во всех классах нужно ввести инициализаторы (защищённые конструктор по умолчанию или конструкторы с фиктивным параметром) и в конструкторах потомка явно задавать именно их (чтобы подавить вызов конструкторов вместо инициализаторов предков). Если же код конструкторов выносить в отдельные (виртуальные) методы, то можно будет вызывать их в конструкторах потомков.



С деструкторами сложнее, поскольку в классе их не может быть более одного, поэтому можно ввести отдельные методы (типа shutdown и destroy в TV).

Теперь остаётся либо убрать деструкторы (хотя придётся явно вызывать методы деструкции), либо ввести общий признак, запрещающий деструкторам предков разрушать, и при переопределении метода деструкции переопределять также деструктор. И не забывайте делать их виртуальными!

В качестве примера можно привести преобразование следующего фрагмента, содержащего типичную ошибку, в правильный:

class PrintFile public:

PrintFile(char name[]) Печaть(GetFileName(name, MyExt())); virtual const char *MyExt() return xxx ;

class PrintAnotherTypeOfFile :public PrintFile public:

PrintAnotherTypeOfFile(char name[]) :PrintFile(name) const char *MyExt() return yyy ;

После преобразования получаем следующее:

class PrintFile

enum Init Init; Тип фиктивного параметра protected: Инициализатор; здесь можно заменить на дефолт конструктор PrintFile(Init ).

Можно добавить несколько конструкторов с другими именами, или, если конструкторы не виртуальные, можно использовать полиморфизм:

bool construct(char name[])

return Печaть(GetFileName(name,MyExt()));

public:

... Код вынесен в отдельный метод для использования в потомках

PrintFile(char name[]) construct(name); virtual const char *MyExt() return xxx ;

class PrintAnotherTypeOfFile :public PrintFile

... Здесь инициализатор пропущен (никто не наследует)



public:

... Конструктор; использует конструктор предка, с виртуальностью;

... указание инициализатора обязательно PrintAnotherTypeOfFile(char name[]) :PrintFile(Init) construct(name);

const char *MyExt() return yyy ; Что такое NAN?

Специальное значение вещественного числа, обозначающее не-число - Non-a-Number. Имеет характеристику (смещенный порядок) из всех единиц, любой знак и любую мантиссу за

исключением .00 00 (такая мантисса обозначает бесконечность).

Имеются даже два типа не чисел:

SNAN - Signalling NAN (сигнализирующие не-числа) - старший бит мантиссы=0

QNAN - Quiet NAN (тихие не-числа) - старший бит мантиссы = 1.

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

QNAN=11 11.100 00 (называется еще вещественной

неопределенностью ), формируется FPU при выполнении недействительной операции, делении 0 на 0, умножении 0 на бесконечность, извлечении корня FSQRT, вычислении логарифма FYL2X отрицательного числа, и т.д. при условии, что обработчик таких особых случаев замаскирован (регистр CW, бит IM=1). В противном случае вызывается обработчик прерывания (Int 10h) и операнды остаются неизменными.

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

Как выключить оптимизацию и как longjmp может привести к баге без этого?

Иногда бывает необходимо проверить механизм генерации кода, скорость работы с какой-нибудь переменной или просто



1 ... 157 158 159 [ 160 ] 161 162 163 ... 210

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика