Поделиться через


Неявная упаковка-преобразование типов значений

Упаковка-преобразование типов значений в Visual C++ изменена по сравнению с управляемыми расширениями для C++.

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

Проблема иерархии виртуальных базовых классов заключается в том, что ответственность за инициализацию общих виртуальных дочерних элементов смещается при каждом очередном наследовании. Например, если определить базовый класс, для инициализации которого требуется выделение буфера, указанный пользователем размер такого буфера может быть передан конструктору как аргумент. Затем, если выполнить два последовательных наследования, назовем их inputb и outputb, то каждое из них предоставит конструктору базового класса определенное значение. Теперь, после выполнения наследования класса in_out от inputb и outputb, ни одно из значений, переданных общему дочернему объекту виртуального базового класса, не может быть определено.

Таким образом, в оригинальной структуре языка Страуструп запретил явную инициализацию виртуальных базовых классов в пределах списка инициализации членов конструктора производного класса. Хотя проблема и была решена, на практике же невозможность направления инициализации виртуальных базовых классов оказалась нецелесообразной. Кит Горлен из Национального института здравоохранения, который создал свободно распространяемую версию библиотеки коллекций SmallTalk, названную "nihcl", сыграл главную роль в убеждении Страуструпа в том, что структуру языка необходимо сделать более гибкой.

Принцип объектно-ориентированной структуры иерархии предполагает, что производный класс должен быть связан только с открытой реализацией непосредственных базовых классов. Для обеспечения гибкости структуры инициализации для виртуального наследования Страуструп был вынужден нарушить такой принцип. Производные классы, дальше всего отстоящие от базового в иерархии, ответственны за весь процесс инициализации виртуальных дочерних объектов независимо от их удаленности от базового класса. Например, и inputb, и outputb ответственны за явную инициализацию своего непосредственного виртуального базового класса. Когда in_out наследует от inputb и outputb одновременно, in_out становится ответственным за инициализацию удаленного виртуального базового класса, а инициализация, выполняющаяся явно в пределах inputb и outputb подавляется.

Это обеспечивает гибкость, требуемую разработчиками языка, но за счет усложнения семантики. Необходимость в таком усложнении пропадает, если ввести ограничения для виртуального базового класса, сделав его без состояния и разрешив ему самому указывать интерфейс. Это — рекомендуемая идиома структуры С++. В рамках программирования в среде CLR это возведено в ранг политик в отношении типов интерфейсов.

Ниже представлен пример простого кода и в этом случае явная упаковка не требуется:

// Managed Extensions for C++ requires explicit __box operation
int my1DIntArray __gc[] = { 1, 2, 3, 4, 5 };
Object* myObjArray __gc[] = { 
   __box(26), __box(27), __box(28), __box(29), __box(30)
};

Console::WriteLine( "{0}\t{1}\t{2}", __box(0),
   __box(my1DIntArray->GetLowerBound(0)),
   __box(my1DIntArray->GetUpperBound(0)) );

Как можно заметить, упаковка происходит. В Visual C++ упаковка типа значения является неявной:

// new syntax makes boxing implicit
array<int>^ my1DIntArray = {1,2,3,4,5};
array<Object^>^ myObjArray = {26,27,28,29,30};

Console::WriteLine( "{0}\t{1}\t{2}", 0, 
   my1DIntArray->GetLowerBound( 0 ), 
   my1DIntArray->GetUpperBound( 0 ) );

См. также

Ссылки

Упаковка-преобразование (расширения компонентов C++)

Основные понятия

Типы значений и их режимы работы (C++/CLI)