Трассировка и отладка в .NET


Ограничения на использование управляемых типов в C++



Ограничения на использование управляемых типов в C++

К сожалению, существует множество правил, которые ограничивают использование управляемых типов (классов, структур, интерфейсов), что ведет к затруднениям в работе с ними по сравнению с традиционными неуправляемыми типами в C++. Эти правила также оказывают некоторое влияние на то, как управляемый и неуправляемый коды могут взаимодействовать друг с другом.
1. Управляемый тип не может быть наследован из неуправляемого типа. С другой стороны, неуправляемый тип не может быть наследован из управляемого типа. Это значит, что структуры иерархий наследственности управляемых и неуправляемых классов всегда отделены друг от друга.
2. Управляемые типы не могут иметь друзей (т.е. дружественных функций, классов, структур и интерфейсов). Естественно, данное правило не распространяется на неуправляемые классы C++. Это, конечно, может быть и не так важно для многих программистов, ведь многие рассматривают дружественность как нарушение важной концепции объектно-ориентированного программирования, называемой инкапсуляцией. Неуправляемые типы могут иметь друзей, как и классы в традиционном C++; однако неуправляемые типы могут иметь друзей только из числа неуправляемых типов.
3. В отличие от неуправляемых типов, управляемые не поддерживают множественную наследуемость реализации. Однако как управляемые, так и неуправляемые типы поддерживают множественную наследуемость интерфейсов. Возможность наследовать только одну реализацию является еще одним ограничением, с которым могут смириться многие программисты. Несмотря на то, что традиционный C++ поддерживает множественную наследуемость реализаций, большинство объектно-ориентированных языков (в том числе Java и Smalltalk) ее не поддерживают. Даже модель компонентных объектов Microsoft (COM), которая на двоичном уровне основывается на таблице виртуальных функций в стиле C++, не поддерживает эту возможность.
4. Управляемый тип может, очевидно, содержать член, который является указателем на управляемый объект. Управляемый тип также может содержать элемент данных, который является неуправляемым объектом или указателем на таковой. С другой стороны, неуправляемый тип не может включать в себя экземпляр управляемого типа или указатель на таковой. Все, что здесь сказано, касается не только указателей, но также и ссылок.
5. Неуправляемый класс, в котором не указан явно базовый класс, является независимым корневым классом. В то же время, управляемый класс, в котором не указан явно ни один класс в качестве базового, является производным от корневого класса System: :Object (Система::Объект).


6. К объекту, участвующему в сборке мусора (т.е. к экземпляру управляемого класса, который использует ключевое слово _дс (сборщик мусора), а не _value (значение) или _поде), можно получить доступ только посредством указателя (или ссылки) на объект в управляемой динамически распределяемой области памяти. Это является отличием от неуправляемых типов, которые могут содержаться либо непосредственно в переменной типа значения, либо к ним можно получить доступ посредством указателя на неуправляемую динамически распределяемую область памяти.
Перечисленные правила использования управляемых типов в C++ подытожены в предлагаемом примере программы. Комментарии помогут вам понять все эти сложные правила. Если вы откроете проект ManagedAndUnmanagedTypes и попробуете раскомментировать каждый из тех операторов (лучше по одному за один проход), который вызывает ошибку компилятора, вы лучше поймете каждое из правил. Всего лишь щелкните на интересующей вас ошибке в окне Task List (Список задач), а затем нажмите F1 для получения документации, в которой разъясняется суть ошибки. И, конечно, двойной щелчок на ошибке в окне Task List (Список задач) приведет вас к соответствующему оператору в окне редактора исходного кода программы.

//ManagedAndUnmanagedTypes.срр
fusing <mscorlib.dll>
using namespace System;
// использование пространства имен Система;
#pragma warning(disable : 4101)
// *pragma предупреждение (отключите: 4101)
// игнорировать отсутствие ссылок на локальные переменные (unref
local)
_gc class MemberManagedClass {};
// используется как элемент данных
// класс сборщика мусора MemberManagedClass {};
_nogc class MemberUnmanagedClass {};
// класс MemberUnmanagedClass используется как элемент данных
_gc class FriendManagedClass {};
// класс сборщика мусора FriendManagedClass используется как друг
_nogc class FriendUnmanagedClass {};
// класс FriendUnmanagedClass используется как друг
_gc class ManagedClass
// класс сборщика мусора ManagedClass
{
public:
MemberUnmanagedClass urn; //OK: внедренный неуправляемый MemberUnmanagedClass *pum; //OK: указатель на неуправляемый MemberUnmanagedClass &rum; //OK: ссылка на неуправляемый
//MemberManagedClass m; // Ошибка: не любит стека
MemberManagedClass *pm; //OK: указатель на управляемый
MemberManagedClass &rm; //OK: ссылка на управляемый
ManagedClass() : // необходим для инициализации ссылки
rm(*new MemberManagedClass), // требуется компилятором! rum(*new MemberUnmanagedClass), // требуется компилятором! pm(new MemberManagedClass) // не требуется компилятором
{}
// Ошибки: не может иметь никаких друзей // в управляемом классе //friend FriendManagedClass; // друг //friend FriendUnmanagedClass; // друг };
_nogc class UnmanagedClass
// класс UnmanagedClass
{
public:
MemberUnmanagedClass um; //OK: внедренный неуправляемый MemberUnmanagedClass *pum; //OK: указатель на неуправляемый MemberUnmanagedClass Srum; //OK: ссылка на неуправляемый
//MemberManagedClass m; // Ошибка: не любит стека
//MemberManagedClass *pm;
// Ошибка: управляемый* в неуправляемом
MemberManagedClass &rm; //OK: ссылка на управляемый (???)
UnmanagedClass() : // необходим для инициализации ссылки
rm(*new MemberManagedClass), // требуется компилятором! rum(*new MemberUnmanagedClass) // требуется компилятором!
{}
// Ошибка: нельзя объявить управляемый друг // в неуправляемом
//friend FriendManagedClass; // друг friend FriendUnmanagedClass; // друг - OK
};
_gc class SuperManagedClass {};
// класс сборщика мусора SuperManagedClass
_nogc class SuperUnmanagedClass {}; // класс SuperUnmanagedClass
// ошибка: управляемый тип не может происходить
//от неуправляемого типа
//_gc class BadSubManagedClass : SuperUnmanagedClass {};
// класс сборщика мусора
// BadSubManagedClass: SuperUnmanagedClass
// ошибка: неуправляемый тип не может происходить
//от управляемого типа
//_nogc class BadSubUnmanagedClass : SuperManagedClass {};
// класс BadSubUnmanagedClass: SuperManagedClass {};
//OK: can derive from machine managed/unmanaged super class
// OK: может происходить от суперкласса,
// управляемого/неуправляемого машиной
_gc class OKSubManagedClass : public SuperManagedClass {};
// класс сборщика мусора
// OKSubManagedClass: SuperManagedClass
_nogc class OKSubUnmanagedClass : SuperUnmanagedClass {};
// класс OKSubUnmanagedClass: SuperUnmanagedClass
void main(void) {
UnmanagedClass *pumc = new UnmanagedClass;
// старый C++
UnmanagedClass umc; // старый C++
UnmanagedClass srumc = *new UnmanagedClass;
// старый C++
ManagedClass *pmc = new ManagedClass;
//OK: управляемая динамически распределяемая
// область памяти
//ManagedClass me; // Ошибка: боится стека
ManagedClass &rmc = *new ManagedClass;
// OK: управляемая динамически распределяемая // область памяти
}




Содержание раздела