Kelas dan struktur ref (C++/CX)

C++/CX mendukung kelas ref yang ditentukan pengguna dan struktur ref, dan kelas nilai dan struktur nilai yang ditentukan pengguna. Struktur data ini adalah kontainer utama di mana C++/CX mendukung sistem jenis Windows Runtime. Kontennya dipancarkan ke metadata sesuai dengan aturan tertentu, dan ini memungkinkan mereka untuk diteruskan antara komponen Windows Runtime dan aplikasi Platform Windows Universal yang ditulis dalam C++ atau bahasa lain.

Kelas ref atau struktur ref memiliki fitur-fitur penting ini:

  • Ini harus dideklarasikan dalam namespace, pada cakupan namespace, dan di namespace layanan tersebut mungkin memiliki aksesibilitas publik atau privat. Hanya jenis publik yang dipancarkan ke metadata. Definisi kelas publik berlapis tidak diizinkan, termasuk kelas enum publik berlapis. Untuk informasi selengkapnya, lihat Namespace dan Visibilitas Jenis.

  • Ini mungkin berisi sebagai anggota C++/CX termasuk kelas ref, kelas nilai, struktur ref, struktur nilai, atau struktur nilai nullable. Ini mungkin juga berisi jenis skalar seperti float64, , booldan sebagainya. Ini mungkin juga berisi jenis C++ standar seperti std::vector atau kelas kustom, selama tidak publik. Konstruksi C++/CX mungkin memiliki publicaksesibilitas , protected, internal, private, atau protected private . Semua public atau protected anggota dipancarkan ke metadata. Jenis C++ standar harus memiliki private, internal, atau protected private aksesibilitas, yang mencegahnya dipancarkan ke metadata.

  • Ini dapat mengimplementasikan satu atau beberapa kelas antarmuka atau struktur antarmuka.

  • Ini dapat mewarisi dari satu kelas dasar, dan kelas dasar itu sendiri memiliki batasan tambahan. Warisan dalam hierarki kelas ref publik memiliki lebih banyak batasan daripada warisan di kelas ref privat.

  • Ini mungkin tidak dinyatakan sebagai generik. Jika memiliki aksesibilitas privat, itu mungkin templat.

  • Masa pakainya dikelola oleh penghitungan referensi otomatis.

Deklarasi

Fragmen kode berikut mendeklarasikan Person kelas ref. Perhatikan bahwa jenis C++ std::map standar digunakan dalam anggota privat, dan antarmuka Windows Runtime IMapView digunakan di antarmuka publik. Perhatikan juga bahwa "^" ditambahkan ke deklarasi jenis referensi.

// #include <map>
namespace WFC = Windows::Foundation::Collections;
namespace WFM = Windows::Foundation::Metadata;

[WFM::WebHostHidden]
ref class Person sealed
{
public:
    Person(Platform::String^ name);
    void AddPhoneNumber(Platform::String^ type, Platform::String^ number);
    property WFC::IMapView<Platform::String^, Platform::String^>^ PhoneNumbers
    { 
        WFC::IMapView<Platform::String^, Platform::String^>^ get();
    }
private:
    Platform::String^ m_name;
    std::map<Platform::String^, Platform::String^> m_numbers;
};

implementasi

Contoh kode ini menunjukkan implementasi Person kelas ref:

#include <collection.h>
using namespace Windows::Foundation::Collections;
using namespace Platform;
using namespace Platform::Collections;

Person::Person(String^ name): m_name(name) { }
void Person::AddPhoneNumber(String^ type, String^ number)
{
    m_numbers[type] = number;
}
IMapView< String^, String^>^ Person::PhoneNumbers::get()
{
    // Simple implementation. 
    return ref new MapView< String^, String^>(m_numbers);
}

Penggunaan

Contoh kode berikutnya menunjukkan bagaimana kode klien menggunakan Person kelas ref.

using namespace Platform;

Person^ p = ref new Person("Clark Kent");
p->AddPhoneNumber("Home", "425-555-4567");
p->AddPhoneNumber("Work", "206-555-9999");
String^ workphone = p->PhoneNumbers->Lookup("Work");

Anda juga dapat menggunakan semantik tumpukan untuk mendeklarasikan variabel kelas ref lokal. Objek seperti itu bersifat seperti variabel berbasis tumpukan meskipun memori masih dialokasikan secara dinamis. Salah satu perbedaan penting adalah Anda tidak dapat menetapkan referensi pelacakan (%) ke variabel yang dideklarasikan dengan menggunakan semantik tumpukan; ini menjamin bahwa jumlah referensi dikurangi menjadi nol ketika fungsi keluar. Contoh ini menunjukkan kelas Uriref dasar , dan fungsi yang menggunakannya dengan semantik tumpukan:

void DoSomething()
{
    Windows::Foundation::Uri docs("http://docs.microsoft.com");
    Windows::Foundation::Uri^ devCenter = docs.CombineUri("/windows/");
    // ... 
} // both variables cleaned up here.

Manajemen memori

Anda mengalokasikan kelas ref dalam memori dinamis dengan menggunakan ref new kata kunci.

MyRefClass^ myClass = ref new MyRefClass();

Operator ^ handle-to-object dikenal sebagai topi dan pada dasarnya adalah pointer pintar C++. Memori yang ditujukan untuk secara otomatis dihancurkan ketika topi terakhir keluar dari cakupan atau secara eksplisit diatur ke nullptr.

Menurut definisi, kelas ref memiliki semantik referensi. Saat Anda menetapkan variabel kelas ref, itu adalah handel yang disalin, bukan objek itu sendiri. Dalam contoh berikutnya, setelah penugasan, dan myClassmyClass2 arahkan ke lokasi memori yang sama.

MyRefClass^ myClass = ref new MyRefClass();
MyRefClass^ myClass2 = myClass;

Ketika kelas ref C++/CX dibuat, memorinya diinisialisasi nol sebelum konstruktornya dipanggil; oleh karena itu tidak perlu menginisialisasi nol anggota individu, termasuk properti. Jika kelas C++/CX berasal dari kelas Windows Runtime C++ Library (WRL), hanya bagian kelas turunan C++/CX yang diinisialisasi nol.

Anggota

Kelas ref dapat berisi publicanggota fungsi , protected, dan private ; hanya public dan protected anggota yang dipancarkan ke dalam metadata. Kelas berlapis dan kelas ref diizinkan tetapi tidak dapat .public Bidang publik tidak diperbolehkan; anggota data publik harus dinyatakan sebagai properti. Anggota data internal privat atau terlindungi mungkin berupa bidang. Secara default di kelas ref, aksesibilitas semua anggota adalah private.

Struktur ref sama dengan kelas ref, kecuali bahwa secara default anggotanya memiliki public aksesibilitas.

Ref public class atau ref struct dipancarkan dalam metadata, tetapi untuk dapat digunakan dari aplikasi Platform Windows Universal lain dan komponen Windows Runtime harus memiliki setidaknya satu konstruktor publik atau terlindungi. Kelas ref publik yang memiliki konstruktor publik juga harus dinyatakan sebagai sealed untuk mencegah derivasi lebih lanjut melalui antarmuka biner aplikasi (ABI).

Anggota publik mungkin tidak dideklarasikan sebagai const karena sistem jenis Windows Runtime tidak mendukung const. Anda dapat menggunakan properti statis untuk mendeklarasikan anggota data publik dengan nilai konstanta.

Saat Anda menentukan kelas ref publik atau struktur, pengkompilasi menerapkan atribut yang diperlukan ke kelas dan menyimpan informasi tersebut dalam file .winmd aplikasi. Namun, saat Anda menentukan kelas ref publik yang belum disegel, terapkan Windows::Foundation::Metadata::WebHostHidden atribut secara manual untuk memastikan bahwa kelas tidak terlihat oleh aplikasi Platform Windows Universal yang ditulis dalam JavaScript.

Kelas ref dapat memiliki jenis C++ standar, termasuk const jenis, di anggota , internal, atau protected private apa punprivate.

Kelas ref publik yang memiliki parameter jenis tidak diizinkan. Kelas ref generik yang ditentukan pengguna tidak diizinkan. Kelas ref privat, internal, atau privat yang dilindungi mungkin merupakan templat.

Penghancur

Di C++/CX, memanggil delete destruktor publik memanggil destruktor terlepas dari jumlah referensi objek. Perilaku ini memungkinkan Anda menentukan destruktor yang melakukan pembersihan kustom sumber daya non-RAII dengan cara yang deterministik. Namun, bahkan dalam hal ini, objek itu sendiri tidak dihapus dari memori. Memori untuk objek hanya dikosongkan ketika jumlah referensi mencapai nol.

Jika destruktor kelas tidak bersifat publik, maka hanya dipanggil ketika jumlah referensi mencapai nol. Jika Anda memanggil delete objek yang memiliki destruktor privat, pengkompilasi memunculkan peringatan C4493, yang mengatakan "hapus ekspresi tidak berpengaruh karena destruktor <nama> jenis tidak memiliki aksesibilitas 'publik'."

Destruktor kelas ref hanya dapat dinyatakan sebagai berikut:

  • publik dan virtual (diizinkan pada jenis yang disegel atau tidak tersegel)

  • privat dan non-virtual yang dilindungi (hanya diperbolehkan pada jenis yang tidak disegel)

  • privat dan non-virtual (hanya diperbolehkan pada jenis yang disegel)

Tidak ada kombinasi lain dari aksesibilitas, virtualness, dan sealedness yang diizinkan. Jika Anda tidak secara eksplisit menyatakan destruktor, kompilator menghasilkan destruktor virtual publik jika kelas dasar jenis atau anggota apa pun memiliki destruktor publik. Jika tidak, kompilator menghasilkan destruktor non-virtual privat yang dilindungi untuk jenis yang tidak tersegel, atau destruktor non-virtual privat untuk jenis yang disegel.

Perilaku tidak ditentukan jika Anda mencoba mengakses anggota kelas yang telah menjalankan destruktornya; kemungkinan besar akan menyebabkan program mengalami crash. Memanggil delete t jenis yang tidak memiliki destruktor publik tidak berpengaruh. Memanggil delete this pada jenis atau kelas dasar yang memiliki dikenal private atau protected private destruktor dari dalam hierarki jenisnya juga tidak berpengaruh.

Ketika Anda mendeklarasikan destruktor publik, pengkompilasi menghasilkan kode sehingga kelas ref mengimplementasikan Platform::IDisposable dan destruktor mengimplementasikan Dispose metode . Platform::IDisposable adalah proyeksi C++/CX dari Windows::Foundation::IClosable. Jangan pernah mengimplementasikan antarmuka ini secara eksplisit.

Warisan

Platform::Object adalah kelas dasar universal untuk semua kelas ref. Semua kelas ref secara implisit dapat dikonversi ke Platform::Object dan dapat menimpa Object::ToString. Namun, model pewarisan Windows Runtime tidak dimaksudkan sebagai model pewarisan umum; di C++/CX ini berarti bahwa kelas ref publik yang ditentukan pengguna tidak dapat berfungsi sebagai kelas dasar.

Jika Anda membuat kontrol pengguna XAML, dan objek berpartisipasi dalam sistem properti dependensi, maka Anda dapat menggunakan Windows::UI::Xaml::DependencyObject sebagai kelas dasar.

Setelah Anda menentukan kelas MyBase yang belum disegel yang mewarisi dari DependencyObject, kelas ref publik atau privat lainnya di komponen atau aplikasi Anda dapat diwarisi dari MyBase. Warisan dalam kelas ref publik hanya boleh dilakukan untuk mendukung penggantian metode virtual, identitas polimorfik, dan enkapsulasi.

Kelas ref dasar privat tidak diperlukan untuk berasal dari kelas yang tidak tersegel yang ada. Jika Anda memerlukan hierarki objek untuk memodelkan struktur program Anda sendiri atau untuk mengaktifkan penggunaan kembali kode, gunakan kelas ref privat atau internal, atau lebih baik lagi, kelas C++ standar. Anda dapat mengekspos fungsionalitas hierarki objek privat melalui pembungkus kelas ref yang disegel publik.

Kelas ref yang memiliki konstruktor publik atau terlindungi di C++/CX harus dinyatakan sebagai disegel. Pembatasan ini berarti bahwa tidak ada cara untuk kelas yang ditulis dalam bahasa lain seperti C# atau Visual Basic untuk mewarisi dari jenis yang Anda deklarasikan dalam komponen Windows Runtime yang ditulis dalam C++/CX.

Berikut adalah aturan dasar untuk warisan di C++/CX:

  • Kelas ref dapat mewarisi langsung dari paling banyak satu kelas ref dasar, tetapi dapat mengimplementasikan sejumlah antarmuka.

  • Jika kelas memiliki konstruktor publik, kelas harus dinyatakan sebagai disegel untuk mencegah derivasi lebih lanjut.

  • Anda dapat membuat kelas dasar yang tidak tersegel publik yang memiliki konstruktor privat internal atau terlindungi, asalkan kelas dasar berasal secara langsung atau tidak langsung dari kelas dasar yang tidak tersegel yang ada seperti Windows::UI::Xaml::DependencyObject. Pewarisan kelas ref yang ditentukan pengguna di seluruh file .winmd tidak didukung; namun, kelas ref dapat mewarisi dari antarmuka yang ditentukan dalam file .winmd lain. Anda dapat membuat kelas turunan dari kelas ref dasar yang ditentukan pengguna hanya dalam komponen Windows Runtime yang sama atau aplikasi Platform Windows Universal.

  • Untuk kelas ref, hanya pewarisan publik yang didukung.

    ref class C{};
    public ref class D : private C //Error C3628
    {};
    

Contoh berikut menunjukkan cara mengekspos kelas ref publik yang berasal dari kelas ref lain dalam hierarki warisan.

namespace InheritanceTest2 
{
    namespace WFM = Windows::Foundation::Metadata;

    // Base class. No public constructor.
    [WFM::WebHostHidden]
    public ref class Base : Windows::UI::Xaml::DependencyObject
    {
    internal:
        Base(){}
    protected:
        virtual void DoSomething (){}
        property Windows::UI::Xaml::DependencyProperty^ WidthProperty;
    };

    // Class intended for use by client code across ABI.
    // Declared as sealed with public constructor.
    public ref class MyPublicClass sealed : Base
    {
    public:
        MyPublicClass(){}
        //...
    };
}

Baca juga

Sistem Jenis
Kelas dan struktur nilai
Referensi Bahasa C++/CX
Referensi Namespace