Dalam pemrograman, introspeksi dan refleksi adalah konsep yang melibatkan pemeriksaan dan modifikasi struktur dan perilaku komponen perangkat lunak saat runtime.

Introspeksi

Introspeksi adalah kemampuan suatu program untuk memeriksa struktur dan propertinya sendiri. Melalui introspeksi, suatu program dapat secara dinamis mengakses informasi tentang dirinya sendiri, seperti jenis suatu objek, metode yang didukungnya, dan properti yang dimilikinya. Hal ini memungkinkan program untuk menyesuaikan perilakunya berdasarkan informasi yang tersedia, yang sangat berguna dalam skenario yang melibatkan pembuatan kode dinamis, serialisasi objek, debugging, dan kerangka kerja seperti pengujian unit atau injeksi ketergantungan.

Cerminan

Refleksi melangkah lebih jauh dari introspeksi dengan memungkinkan suatu program tidak hanya memeriksa tetapi juga memodifikasi struktur dan perilakunya sendiri pada waktu proses. Dengan refleksi, suatu program dapat secara dinamis membuat objek baru, memanggil metode, mengakses atau memodifikasi bidang, dan bahkan menghasilkan kode secara dinamis. Refleksi memberikan kemampuan untuk melakukan teknik metaprogramming yang kuat, sehingga memungkinkan untuk memperluas fungsionalitas program, menerapkan penyesuaian, atau mengimplementasikan fitur yang tidak ada pada waktu kompilasi. Namun, penting untuk dicatat bahwa refleksi adalah alat yang ampuh yang harus digunakan dengan hati-hati, karena dapat meningkatkan kompleksitas dan mempengaruhi kinerja jika digunakan secara tidak tepat.

Introspeksi dan refleksi umumnya digunakan dalam bahasa yang diketik secara dinamis seperti Python, Ruby, dan JavaScript. Mereka menawarkan fleksibilitas dan dinamisme dalam eksekusi program, memungkinkan pengembang untuk menulis kode yang lebih umum, mudah beradaptasi, dan diperluas.

C++ menyediakan beberapa dukungan untuk introspeksi melalui fitur seperti informasi tipe, yang memungkinkan Anda mengambil informasi tentang tipe pada waktu kompilasi. Operator typeid dapat digunakan untuk mendapatkan informasi tipe saat runtime, memungkinkan Anda membandingkan tipe atau memeriksa namanya. Selain itu, kelas std::type_info menyediakan fungsionalitas dasar untuk bekerja dengan informasi tipe. Namun, C++ tidak menyediakan kemampuan introspeksi bawaan yang ekstensif seperti mengakses metode atau properti objek secara dinamis.

C++ tidak menyediakan kemampuan introspeksi bawaan yang ekstensif seperti Python atau Java. Hal ini karena C++ pada dasarnya adalah bahasa yang diketik secara statis, yang berarti bahwa sebagian besar perilakunya ditentukan pada waktu kompilasi. Oleh karena itu, tingkat introspeksi dan refleksi yang tersedia dalam C++ lebih terbatas dibandingkan dengan bahasa dinamis. Ada perpustakaan dan teknik yang dapat memfasilitasi bentuk refleksi terbatas dalam C++, seperti Boost.Reflection atau solusi pihak ketiga. Namun, solusi ini tidak memberikan tingkat introspeksi dan refleksi yang sama seperti bahasa dinamis seperti Python atau Java.

Introspeksi dengan Qt

Introspeksi objek adalah fitur canggih dalam kerangka Qt yang memungkinkan Anda memeriksa dan mengumpulkan informasi tentang objek saat runtime. Dengan menggunakan kemampuan introspeksi Qt, Anda dapat mengambil detail seperti nama kelas, properti, sinyal, dan metode suatu objek secara dinamis.

Pada artikel ini, kita akan mengeksplorasi contoh yang menunjukkan cara menggunakan introspeksi di Qt. Mari kita perhatikan contoh di mana kita memiliki kelas Person yang berasal dari QObject. Kelas Person memiliki dua properti: name dan age. Selain itu, ini juga mendefinisikan dua sinyal: nameChanged dan ageChanged. Tujuannya adalah menggunakan introspeksi untuk mengambil informasi tentang properti dan sinyal ini pada waktu proses.

Orang.h

#pragma once

#include <QObject>

class Person : public QObject
{
    Q_OBJECT

    Q_PROPERTY(QString name READ getName WRITE setName NOTIFY nameChanged)
    Q_PROPERTY(int age READ getAge WRITE setAge NOTIFY ageChanged)
public:
    Person(QObject *parent = nullptr);
    virtual ~Person();
    QString getName() const { return m_name; }
    void    setName(const QString &name)
    {
        m_name = name;
        emit nameChanged();
    }
    int  getAge() const { return m_age; }
    void setAge(int age)
    {
        m_age = age;
        emit ageChanged();
    }
signals:
    void nameChanged();
    void ageChanged();

private:
    QString m_name;
    int     m_age;
};

utama.cpp

#include <QCoreApplication>
#include <QDebug>
#include <QMetaObject>
#include <QMetaProperty>
#include <QMetaMethod>

#include "Person.h"

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    Person           obj;
    obj.setObjectName("myObject");

    // Get the meta-object of the object
    const QMetaObject *metaObject = obj.metaObject();

    // Get the class name
    QString className = metaObject->className();
    qDebug() << "Class Name:" << className;

    // Get the number of properties
    int propertyCount = metaObject->propertyCount();
    qDebug() << "Property Count:" << propertyCount;

    // Iterate over the properties
    for ( int i = 0; i < propertyCount; ++i )
    {
        QMetaProperty property = metaObject->property(i);
        qDebug() << "Property Name:" << property.name() << "Type:" << property.typeName()
                 << "Value:" << property.read(&obj);
    }

    // Get the number of methods
    int methodCount = metaObject->methodCount();
    qDebug() << "Method Count:" << methodCount;

    // Iterate over the methods
    for ( int i = 0; i < methodCount; ++i )
    {
        QMetaMethod method = metaObject->method(i);
        qDebug() << "Method Signature:" << method.methodSignature();
    }
    return app.exec();
}

Fungsi main() mendemonstrasikan kemampuan introspeksi dengan menggunakan kelas QMetaObject untuk mengambil informasi tentang objek saat runtime.

Saat Anda menjalankan kode ini, hasilnya akan seperti berikut:

Class Name: “Person”
Property Count: 3
Property Name: objectName Type: QString Value: QVariant(QString, “myObject”)
Property Name: name Type: QString Value: QVariant(QString, “”)
Property Name: age Type: int Value: QVariant(int, 0)
Method Count: 7
Method Signature: “destroyed(QObject*)”
Method Signature: “destroyed()”
Method Signature: “objectNameChanged(QString)”
Method Signature: “deleteLater()”
Method Signature: “_q_reregisterTimers(void*)”
Method Signature: “nameChanged()”
Method Signature: “ageChanged()”

Seperti yang Anda lihat, kode tersebut mengambil nama kelas, jumlah properti, nama properti, tipe, dan nilai, serta tanda tangan metode. Ini menunjukkan bagaimana introspeksi memungkinkan Anda memeriksa dan mengumpulkan informasi tentang properti dan metode objek secara dinamis saat runtime.

Kode sumber artikel ini dapat diunduh dari: