Что такое ref class

ref class and ref struct (C++/CLI and C++/CX)

The ref class or ref struct extensions declare a class or struct whose object lifetime is administered automatically. When the object is no longer accessible or goes out of scope, the memory is released.

All Runtimes

Syntax

Parameters

class_access
(Optional) The accessibility of the class or struct outside the assembly. Possible values are public and private ( private is the default). Nested classes or structs cannot have a class_access specifier.

name
The name of the class or struct.

modifier
(Optional) abstract and sealed are valid modifiers.

inherit_access
(Optional) The accessibility of base_type. The only permitted accessibility is public ( public is the default).

base_type
(Optional) A base type. However, a value type cannot act as a base type.

For more information, see the language-specific descriptions of this parameter in the Windows Runtime and Common Language Runtime sections.

Remarks

For more information on classes and structs, see

Windows Runtime

Remarks

Parameters

base_type
(Optional) A base type. A ref class or ref struct can inherit from zero or more interfaces and zero or one ref types. A value class or value struct can only inherit from zero or more interfaces.

When you declare an object by using the ref class or ref struct keywords, the object is accessed by a handle to an object; that is, a reference-counter pointer to the object. When the declared variable goes out of scope, the compiler automatically deletes the underlying object. When the object is used as a parameter in a call or is stored in a variable, a handle to the object is actually passed or stored.

When you declare an object by using the value class or value struct keywords, the object lifetime of the declared object is not supervised. The object is like any other standard C++ class or struct.

Requirements

Compiler option: /ZW

Common Language Runtime

Remarks

The following table lists differences from the syntax shown in the All Runtimes section that are specific to C++/CLI.

Parameters

base_type
(Optional) A base type. A ref class or ref struct can inherit from zero or more managed interfaces and zero or one ref types. A value class or value struct can only inherit from zero or more managed interfaces.

The ref class and ref struct keywords tell the compiler that the class or structure is to be allocated on the heap. When the object is used as a parameter in a call or is stored in a variable, a reference to the object is actually passed or stored.

The value class and value struct keywords tells the compiler that the value of the allocated class or structure is passed to functions or stored in members.

Источник

Классы и структуры ссылки (C++/CX)

C++/CX поддерживает определяемые пользователем ссылочные классы и Ссылочные структуры, а также пользовательские классы значений и структуры значений. эти структуры данных являются основными контейнерами, по которым C++/cx поддерживает систему типов среда выполнения Windows. их содержимое передается в метаданные в соответствии с определенными правилами, и это позволяет передавать их между компонентами среда выполнения Windows и универсальная платформа Windows приложениями, написанными на C++ или на других языках.

Класс ссылки и структура ссылки имеют следующие основные особенности:

они могут реализовывать один или несколько классов интерфейсов или структур интерфейсов;

они могут наследовать одному базовому классу, а на сами базовые классы налагаются дополнительные ограничения. Наследование в иерархиях открытых классов ссылок имеет больше ограничений, чем наследование закрытых классов ссылок;

они не могут объявляться как универсальные. Если они имеют закрытый доступ, они могут быть шаблонами;

Их время жизни управляется автоматическим подсчетом ссылок.

Объявление

Реализация

Использование

Также можно также объявить локальную переменную класса ссылки с помощью семантики стека. Поведение такого объекта аналогично поведению стековой переменной, несмотря на то что память все же выделяется динамически. Важное отличие заключается в том, что нельзя присвоить отслеживаемую ссылку (%) переменной, объявленной с использованием семантики стека: таким образом гарантируется, что счетчик ссылок уменьшается до нуля, когда выполняется выход из функции. В этом примере показаны базовый класс ссылки Uri и функция, в которой он используется с семантикой стека:

Управление памятью

По определению класс ссылки имеет семантику ссылки. Когда вы присваиваете значение переменной класса ссылки, копируется не сам объект, а его дескриптор. В следующем примере после операции присваивания оба объекта myClass и myClass2 указывают на одно и то же расположение в памяти.

Когда создается экземпляр класса ссылки C++/CX, его память перед вызовом конструктора инициализируется нулями, поэтому такая инициализация для отдельных членов, включая свойства, не требуется. Если класс C++/CX является производным от класса библиотеки C++ для среды выполнения Windows (WRL), инициализация нулями осуществляется только для области производного класса C++/CX.

Члены

При определении открытого класса или структуры ссылок компилятор применяет необходимые атрибуты к классу и сохраняет эти сведения в файле WinMD приложения. однако при определении открытого незапечатанного класса ссылки вручную примените Windows::Foundation::Metadata::WebHostHidden атрибут, чтобы класс не был видимым для универсальная платформа Windows приложений, написанных на JavaScript.

Открытые классы ссылки, имеющие параметры-типы, не допускаются. Определяемые пользователем универсальные классы ссылок не допускаются. Класс ссылки с атрибутами private, internal или protected private может быть шаблоном.

Деструкторы

В C++/CX вызов метода delete в открытом деструкторе вызывает деструктор независимо от счетчика ссылок объекта. Это позволяет определить деструктор, который будет выполнять пользовательскую очистку ресурсов, не относящихся к RAII, детерминированным образом. Однако даже в этом случае сам объект не удаляется из памяти. Память для объекта освобождается, только когда число ссылок достигает нуля.

Если деструктор класса не является общим, он вызывается только в случае, когда число ссылок достигает нуля. При вызове delete для объекта, имеющего закрытый деструктор, компилятор выдает предупреждение C4493, что говорит о том, что выражение delete не действует, так как деструктор не имеет модификатора public.

Деструкторы классов ссылок можно объявлять только следующим образом:

открытый и виртуальный (допускается только для запечатанных и незапечатанных типов);

защищенный закрытый и невиртуальный (допускается только для незапечатанных типов);

закрытый и невиртуальный (допускается только для запечатанных типов).

Никакие другие сочетания режимов доступа, виртуальности и запечатанности не допускаются. Если деструктор явно не объявлен, компилятор создает открытый виртуальный деструктор, если у базового класса типа или любого из его членов имеется открытый деструктор. В противном случае компилятор создает защищенный закрытый невиртуальный деструктор для незапечатанных типов и закрытый невиртуальный деструктор для запечатанных типов.

При попытке обращения к членам класса, для которого уже запускался деструктор, поведение будет неопределенным; это наиболее вероятная причина сбоя программы. При вызове delete t для типа, у которого нет открытого деструктора, ничего не происходит. При вызове delete this для типа или базового класса, не имеющих деструктора private или protected private в иерархии типов, также ничего не происходит.

Наследование

Platform::Object является универсальным базовым классом для всех классов ссылок. Все классы ссылок неявно преобразуются в Platform::Object и могут переопределять Object::ToString. однако модель наследования среда выполнения Windows не предназначена как общая модель наследования; в C++/cx это означает, что определяемый пользователем открытый класс ссылки не может служить базовым классом.

Закрытый базовый класс ссылки не требуется для наследования от существующего незапечатанного класса. Если требуется, чтобы иерархия объектов моделировала собственную структуру программы или обеспечивала повторное использование кода, используйте закрытые или внутренние классы ссылок, а лучше стандартные классы C++. Доступ к функциональности закрытой иерархии объектов можно реализовать с помощью оболочки открытого запечатанного класса ссылки.

Класс ссылки, имеющий открытый или защищенный конструктор в C++/CX, должен быть объявлен как Sealed. это ограничение означает, что для классов, написанных на других языках, таких как C# или Visual Basic, не существует способа наследования от типов, объявляемых в среда выполнения Windows компоненте, написанном на C++/CX.

Ниже приведены основные правила наследования в C++/CX.

классы ссылок могут напрямую наследовать не более чем от одного базового класса, но могут реализовывать любое количество интерфейсов;

если у класса имеется открытый конструктор, он должен объявляться как запечатанный, чтобы запретить его дальнейшее наследование;

для классов ссылок поддерживается только открытое наследование.

В следующем примере показано, как предоставлять доступ к открытому классу ссылки, производному от других классов ссылки в иерархии наследования.

Источник

Ref classes and structs (C++/CX)

The C++/CX supports user-defined ref classes and ref structs, and user-defined value classes and value structs. These data structures are the primary containers by which C++/CX supports the Windows Runtime type system. Their contents are emitted to metadata according to certain specific rules, and this enables them to be passed between Windows Runtime components and Universal Windows Platform apps that are written in C++ or other languages.

A ref class or ref struct has these essential features:

It must be declared within a namespace, at namespace scope, and in that namespace it may have public or private accessibility. Only public types are emitted to metadata. Nested public class definitions are not permitted, including nested public enum classes. For more information, see Namespaces and Type Visibility.

It may implement one or more interface classes or interface structs.

It may inherit from one base class, and base classes themselves have additional restrictions. Inheritance in public ref class hierarchies has more restrictions than inheritance in private ref classes.

It may not be declared as generic. If it has private accessibility, it may be a template.

Its lifetime is managed by automatic reference counting.

Declaration

The following code fragment declares the Person ref class. Notice that the standard C++ std::map type is used in the private members, and the Windows Runtime IMapView interface is used in the public interface. Also notice that the «^» is appended to declarations of reference types.

Implementation

This code example shows an implementation of the Person ref class:

Usage

The next code example shows how client code uses the Person ref class.

Memory management

You allocate a ref class in dynamic memory by using the ref new keyword.

By definition, a ref class has reference semantics. When you assign a ref class variable, it’s the handle that’s copied, not the object itself. In the next example, after assignment, both myClass and myClass2 point to the same memory location.

When a C++/CX ref class is instantiated, its memory is zero-initialized before its constructor is called; therefore it is not necessary to zero-initialize individual members, including properties. If the C++/CX class derives from a Windows Runtime C++ Library (WRL) class, only the C++/CX derived class portion is zero-initialized.

Members

A ref struct is the same as a ref class, except that by default its members have public accessibility.

A public ref class or ref struct is emitted in metadata, but to be usable from other Universal Windows Platform apps and Windows Runtime components it must have at least one public or protected constructor. A public ref class that has a public constructor must also be declared as sealed to prevent further derivation through the application binary interface (ABI).

Public members may not be declared as const because the Windows Runtime type system does not support const. You can use a static property to declare a public data member with a constant value.

Public ref classes that have type parameters are not permitted. User-defined generic ref classes are not permitted. A private, internal, or protected private ref class may be a template.

Destructors

In C++/CX, calling delete on a public destructor invokes the destructor regardless of the object’s reference count. This behavior enables you to define a destructor that performs custom cleanup of non-RAII resources in a deterministic manner. However, even in this case, the object itself is not deleted from memory. The memory for the object is only freed when the reference count reaches zero.

If a class’s destructor is not public, then it is only invoked when the reference count reaches zero. If you call delete on an object that has a private destructor, the compiler raises warning C4493, which says «delete expression has no effect as the destructor of does not have ‘public’ accessibility.»

Ref class destructors can only be declared as follows:

public and virtual (allowed on sealed or unsealed types)

protected private and non-virtual (only allowed on unsealed types)

private and non-virtual (allowed only on sealed types)

No other combination of accessibility, virtualness, and sealedness is allowed. If you do not explicitly declare a destructor, the compiler generates a public virtual destructor if the type’s base class or any member has a public destructor. Otherwise, the compiler generates a protected private non-virtual destructor for unsealed types, or a private non-virtual destructor for sealed types.

The behavior is undefined if you try to access members of a class that has already had its destructor run; it will most likely cause the program to crash. Calling delete t on a type that has no public destructor has no effect. Calling delete this on a type or base class that has a known private or protected private destructor from within its type hierarchy also has no effect.

Inheritance

Platform::Object is the universal base class for all ref classes. All ref classes are implicitly convertible to Platform::Object and can override Object::ToString. However, the Windows Runtime inheritance model not intended as a general inheritance model; in C++/CX this means that a user-defined public ref class cannot serve as a base class.

If you are creating a XAML user control, and the object participates in the dependency property system, then you can use Windows::UI::Xaml::DependencyObject as a base class.

A private base ref class is not required to derive from an existing unsealed class. If you require an object hierarchy to model your own program structure or to enable code reuse, then use private or internal ref classes, or better yet, standard C++ classes. You can expose the functionality of the private object hierarchy through a public sealed ref class wrapper.

A ref class that has a public or protected constructor in C++/CX must be declared as sealed. This restriction means that there is no way for classes that are written in other languages such as C# or Visual Basic to inherit from types that you declare in a Windows Runtime component that’s written in C++/CX.

Here are the basic rules for inheritance in C++/CX:

Ref classes can inherit directly from at most one base ref class, but can implement any number of interfaces.

If a class has a public constructor, it must be declared as sealed to prevent further derivation.

For ref classes, only public inheritance is supported.

The following example shows how to expose a public ref class that derives from other ref classes in an inheritance hierarchy.

Источник

ref class и ref struct (C++/CLI и C++/CX)

Расширения ref class или ref struct объявляют класс или структуру со временем жизни объекта, которое администрируется автоматически. Когда объект становится недоступным или выходит за пределы области, память освобождается.

Все среды выполнения

Синтаксис

Параметры

class_access
(Необязательно) Доступность класса или структуры вне сборки. Возможные значения: public и private ( private используется по умолчанию). Вложенные классы и структуры не могут иметь описатель class_access.

name
Имя класса или структуры.

Модификатор
(Необязательно) Допустимые модификаторы — abstract и sealed.

inherit_access
(Необязательно) Доступность base_type. Единственным разрешенным доступом является public ( public является значением по умолчанию).

base_type
(Необязательно) Базовый тип. Однако тип значения не может действовать как базовый тип.

Дополнительные сведения см. в описаниях этого параметра для конкретного языка в разделах «Среда выполнения Windows» и «Среда CLR».

Комментарии

Дополнительные сведения о классах и структурах см. в разделе

Среда выполнения Windows

Комментарии

Параметры

base_type
(Необязательно) Базовый тип. ref class или ref struct могут наследовать от произвольного числа (включая 0) интерфейсов и от ноля или одного типа ref. value class или value struct могут наследовать только от произвольного числа (включая 0) интерфейсов.

Если объект объявлен с помощью ключевых слов ref class или ref struct, он доступен дескриптору объекта, т. е. указателю счетчика ссылок на объект. Если объявленная переменная выходит за пределы области, компилятор автоматически удаляет базовый объект. Если объект используется в качестве параметра в вызове или хранится в переменной, то обработчик объекта фактически передается или сохраняется.

При объявлении объекта с помощью ключевых слов value class или value struct время жизни объявленного объекта не контролируется. Этот объект аналогичен любому другому стандартному классу или структуре C++.

Требования

Параметр компилятора: /ZW

Среда CLR

Комментарии

В следующей таблице перечислены отличия от синтаксиса, показанного в разделе Все среды выполнения, которые характерны для C++/CLI.

Параметры

base_type
(Необязательно) Базовый тип. ref class или ref struct может наследовать от произвольного числа (включая 0) управляемых интерфейсов и от ноля или одного типа ref. value class или value struct может наследовать только от произвольного числа (включая 0) управляемых интерфейсов.

Ключевые слова ref class и ref struct сообщают компилятору, что класс или структура должны выделяться в куче. Если объект используется в качестве параметра в вызове или хранится в переменной, то ссылка на объект фактически передается или сохраняется.

Ключевые слова value class и value struct сообщают компилятору, что значение выделенного класса или структуры передается функциям или сохраняется в элементах.

Источник

Руководство. Определение и использование классов и структур (C++/CLI)

В этой статье показано, как определить и использовать определяемые пользователем ссылочные типы и типы значений в C++/CLI.

Создание экземпляра объекта

Ссылочные типы (ref) можно создавать только в управляемой куче, а не в стеке или в собственной куче. Экземпляры типов значений можно создавать в стеке или в управляемой куче.

Неявно абстрактные классы

Возможно, не удастся создать объекты из класса, производного от интерфейса. Причиной может быть то, что класс неявно является абстрактным. Дополнительные сведения о абстрактных классах см. в разделе abstract.

Видимость типов

Можно управлять видимостью типов среды CLR. При указании ссылки на сборку вы управляете отображением типов в сборке или их невидимостью за пределами сборки.

Дополнительные сведения см. в разделе Директива using.

Выходные данные

Теперь давайте Перепишем предыдущий пример, чтобы он был создан в виде библиотеки DLL.

В следующем примере показано, как получить доступ к типам за пределами сборки. В этом примере клиент использует компонент, созданный в предыдущем примере.

Выходные данные

Видимость элементов

В этой таблице перечислены результаты различных описателей доступа.

В следующем примере показан открытый тип, который содержит члены, объявленные с помощью различных описателей доступа. Затем он показывает доступ к членам внутри сборки.

Выходные данные

Теперь давайте создадим предыдущий пример в виде библиотеки DLL.

В следующем примере используется компонент, созданный в предыдущем примере. В нем показано, как получить доступ к членам за пределами сборки.

Выходные данные

Открытые и закрытые машинные классы

На собственный тип можно ссылаться из управляемого типа. Например, функция в управляемом типе может принимать параметр, тип которого является структурой машинного кода. Если управляемый тип и функция открыты в сборке, то собственный тип также должен быть открытым.

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

Теперь скомпилируйте клиент:

Статические конструкторы

Тип CLR (например, класс или структура) может иметь статический конструктор, который можно использовать для инициализации статических элементов данных. Статический конструктор вызывается не чаще, и вызывается до первого доступа к статическому члену типа.

Конструктор экземпляра всегда запускается после статического конструктора.

Компилятор не может встроеет вызов конструктора, если класс имеет статический конструктор. Компилятор не может встроеет вызов любой функции-члена, если класс является типом значения, имеет статический конструктор и не имеет конструктора экземпляра. Среда CLR может подставляемь вызов, но компилятор не может.

Определите статический конструктор как закрытую функцию-член, так как она должна вызываться только средой CLR.

Выходные данные

Семантика this указателя

Эти различные семантики this указателя могут вызвать непредвиденное поведение при вызове индексатора по умолчанию. В следующем примере показан правильный способ доступа к индексатору по умолчанию как для ссылочного типа, так и для типа значения.

Выходные данные

Функции скрытия по подписи

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

Для вызова данной функции функция в базовом классе может иметь сигнатуру, которая делает его немного более подходящие, чем функция в производном классе. Однако если функция была явно вызвана для объекта производного класса, вызывается функция в производном классе.

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

В следующем примере показано, что функция в базовом классе не скрыта функцией в производном классе.

Выходные данные

В следующем примере показано, что компилятор Microsoft C++ вызывает функцию в наиболее производном классе, даже если преобразование требуется для сопоставления с одним или несколькими параметрами — и не вызывает функцию в базовом классе, которая лучше соответствует вызову функции.

Выходные данные

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

Выходные данные

Конструкторы копии

Стандарт C++ говорит о том, что конструктор копий вызывается при перемещении объекта, так что объект создается и уничтожается по тому же адресу.

Однако если функция, скомпилированная в MSIL, вызывает собственную функцию, где собственный класс (или несколько) передается по значению, а собственный класс имеет конструктор копии или деструктор, конструктор копии не вызывается и объект уничтожается по адресу, отличному от того, где он был создан. Такое поведение может вызвать проблемы, если класс имеет указатель на себя или если код отслеживает объекты по адресу.

Дополнительные сведения см. в разделе /CLR (компиляция среды CLR).

В следующем примере показано, когда конструктор копии не создается.

Выходные данные

Деструкторы и методы завершения

Деструкторы в ссылочном типе выполняют детерминированную очистку ресурсов. Методы завершения удаляют неуправляемые ресурсы и могут вызываться либо детерминированно деструктором, либо недетерминированными сборщиком мусора. Дополнительные сведения о деструкторах в стандартном C++ см. в разделе деструкторы.

Сборщик мусора среды CLR удаляет неиспользуемые управляемые объекты и освобождает их память, когда они больше не требуются. Однако тип может использовать ресурсы, которые сборщик мусора не знает, как выпустить. Эти ресурсы называются неуправляемыми ресурсами (например, собственными дескрипторами файлов). Рекомендуется освободить все неуправляемые ресурсы в методе завершения. Сборщик мусора освобождает управляемые ресурсы недетерминированным образом, поэтому в методе завершения нельзя ссылаться на управляемые ресурсы. Это связано с тем, что сборщик мусора уже удалил их.

Управляемый тип может также использовать управляемые ресурсы, которые желательно выпустить в детерминированном виде. Сборщик мусора не должен освобождать объект недетерминированным образом в некоторый момент после того, как объект больше не требуется. Детерминированный выпуск ресурсов может значительно повысить производительность.

Компилятор Microsoft C++ позволяет определение деструктора для детерминированной очистки объектов. Используйте деструктор, чтобы освободить все ресурсы, которые нужно выпустить в детерминированном виде. Если имеется метод завершения, вызовите его из деструктора, чтобы избежать дублирования кода.

Если код, использующий тип, не вызывает деструктор, сборщик мусора в конечном итоге освобождает все управляемые ресурсы.

Наличие деструктора не подразумевает наличия метода завершения. Однако присутствие метода завершения предполагает, что необходимо определить деструктор и вызвать метод завершения из этого деструктора. Этот вызов обеспечивает детерминированный выпуск неуправляемых ресурсов.

Вызов деструктора подавляется — с помощью SuppressFinalize— финализации объекта. Если деструктор не вызывается, метод завершения типа в конечном итоге будет вызываться сборщиком мусора.

Можно повысить производительность, вызвав деструктор для детерминированной очистки ресурсов объекта, вместо того, чтобы позволить среде CLR недетерминированно завершать объект.

Код, написанный на Visual C++ и скомпилированный с помощью, /clr выполняет деструктор типа, если:

Объект, созданный с помощью семантики стека, выходит за пределы области. Дополнительные сведения см. в разделе Семантика стека C++ для ссылочных типов.

Во время создания объекта выдается исключение.

Объект является членом объекта, деструктор которого выполняется.

Вы явно вызываете деструктор.

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

При вызове метода для Dispose(void) типа.

Значение, если тип выходит за пределы области действия в using инструкции C#.

Если тип содержит либо метод завершения, либо деструктор, компилятор создает Dispose(bool) метод в соответствии с шаблоном разработки. (Дополнительные сведения см. в разделе шаблон удаления). Вы не можете явно создавать или вызывать Dispose(bool) в Visual C++.

Если тип имеет базовый класс, который соответствует шаблону разработки, деструкторы для всех базовых классов вызываются при вызове деструктора для производного класса. (Если тип написан на Visual C++, компилятор гарантирует, что типы реализуют этот шаблон.) Иными словами, деструктор ссылочного класса привязывается к его основам и элементам, как указано в стандарте C++. Во-первых, выполняется деструктор класса. Затем деструкторы для своих членов запускаются в противоположном порядке, в котором они были созданы. Наконец, деструкторы для своих базовых классов запускаются в противоположном порядке, в котором они были созданы.

Деструкторы и методы завершения не допускаются внутри типов значений или интерфейсов.

Метод завершения может быть определен или объявлен только в ссылочном типе. Как и конструктор, и деструктор, метод завершения не имеет возвращаемого типа.

После запуска метода завершения объекта также вызываются методы завершения в любых базовых классах, начиная с наименее производного типа. Методы завершения для элементов данных не автоматически присоединяются к методу завершения класса.

Если метод завершения удаляет собственный указатель в управляемом типе, необходимо убедиться, что ссылки на или через собственный указатель не были преждевременно собраны. Вызовите деструктор в управляемом типе вместо использования KeepAlive.

Во время компиляции можно определить, имеет ли тип метод завершения или деструктор. Дополнительные сведения см. в статье Compiler Support for Type Traits (C++/CLI and C++/CX) (Поддержка характеристик типов компилятором (C++/CLI and C++/CX)).

В следующем примере показаны два типа: один, содержащий неуправляемые ресурсы, а другой — управляемые ресурсы, которые освобождаются детерминированным образом.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *