|
Программирование >> Разработка устойчивых систем
Точнее, 5*sizeof(int). Компиляторы могут использовать дополнительное выравнивание, поэтому размер объекта по крайней мере не .меньше суммы частей, хотя может превышать ее. ственный способ сделать сравнение осмысленным (то есть повышающее преобразование разрешено всегда), отсюда и истинный результат. Таким образом, при преобразовании типов подобъектов и полных типов применяется соответствующее смещение. Естественно, необходимо организовать специальную проверку нулевых указателей, поскольку автоматическое вычитание смещения при преобразовании подобъ-екта В даст неверный результат, если указатель был равен нулю. По этой причине при преобразовании к В* или из него компилятор генерирует код, который сначала проверяет, не равен ли указатель нулю. Если указатель отличен от нуля, смещение применяется, а если нет, указатель так и остается нулевым. Теперь предположим, что базовых классов несколько и у них в свою очередь имеется общий базовый класс. Как показывает следующий пример, в этом случае производный объект будет содержать несколько копий базового объекта верхнего уровня: : С09:Duplicate.срр Дубликаты подобъектов linclude <iostream> using namespace std: class Top { int X: public: TopCint n) { X = n: } class Left : public Top { int y: public: Left(int m. int n) : Top(m) { у = n: } class Right : public Top { int z: public: RightCint m, int n) : Top(m) { z = n: } class Bottom : public Left, public Right { int w: public: BottomCint i. int j. int k. int m) : Left(i. k). Right(j. k) { w = m: } int mainO { Bottom b(l. 2. 3. 4): cout sizeof b endl: 20 } III:- Поскольку размер b равен 20 байт, полный объект Bottom содержит пять целых чисел. Типичная иерархия наследования в ситуациях такого рода выглядит так: Left Right □Г Bottom Перед вами так называемое ромбовидное наследование , которое лучше было бы изобразить в виде Left Right Bottom Неудобство этого подхода отражается в конструкторе класса Bottom из предыдущего примера. Пользователь думает, что для конструирования необходимы всего четыре числа, но какие аргументы должны передаваться в двух параметрах Left и Right? Хотя такая архитектура не является принципиально ошибочной, обычно это не то, что нужно вашему приложению. Кроме того, проблемы возникают и при попытке преобразовать указатель на Bottom в указатель на Тор. Как было показано ранее, преобразование может потребовать дополнительной настройки адреса в зависимости от смешения подобъекта внутри полного объекта, но в данном случае приходится выбирать между двумя подобъектами Тор. Компилятор не знает, какой именно подобъект он должен выбрать, поэтому такое повышающее преобразование запрещается как неоднозначное. Аналогичные рассуждения объясняют, почему объект Bottom не сможет вызвать функцию, определенную только в Тор. Для такой функции Top::f() вызов b.f() потребует ссылки на подобъект Тор в контексте исполнения, а таких объектов два. Виртуальные базовые классы в подобных ситуациях помогло бы настоящее ромбовидное наследование, при котором один объект Тор совместно используется обоими подобъектами. Left и Right, в полном объекте Bottom, как показано на первой диаграмме. Чтобы добиться этой цели, следует объявить Тор виртуальным базовым классом для Left и Right: : C09:VirtualBase.cpp Совместное использование подобъектов через виртуальный базовый класс base #inclucle <iostream> Мы используем общепринятый термин иерархия , хотя графическое представление отнощений множественного наследования правильнее было бы называть ориентированным ациклическим графом, или решеткой. using namespace std: class Top { protected: int x: public: TopCint n) { X = n: } virtual -Top(){} friend ostream& operator (ostream& os. const Top& t) { return OS t.x: class Left : virtual public Top { protected: int y: public: LeftCint m. int n) : Top(m) { у = n: } class Right : virtual public Top { protected: int z: public: RightCint m, int n) : Top(m) { z = n: } class Bottom : public Left, public Right { int w: public: BottomCint i, int j, int k, int m) : Top(i), Left(0. j). Right(0. k) { w = m: } friend ostream& operator (ostream& os. const Bottoms b) { return OS b.x . b.y . b.z . b.w: int mainO { Bottom b(l. 2. 3. 4): cout sizeof b endl: cout b endl: cout static cast<void*>(&b) endl: Top* p = static cast<Top*>(&b): cout *p endl: cout static cast<void*>(p) endl: cout dynamic cast<void*>(p) endl: } III:- Bee виртуальные базы заданного типа относятся к одному объекту независимо от его местонахождения в иерархии. Таким образом, экземпляр объекта Bottom имеет следующую структуру:
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |