Qtの基礎 - プリプロセッサ

提供:MochiuWiki : SUSE, EC, PCB
ナビゲーションに移動 検索に移動

概要

Qtにおけるプリプロセッサは、標準的なC++プリプロセッサを拡張して、Qtフレームワークに特化した機能を提供している。
この拡張により、開発者はより効率的にQtアプリケーションを作成できるようになる。
また、クロスプラットフォームアプリケーションの開発がより効率的かつ柔軟になっている。

Qt独自のプリプロセッサの主な特徴として、メタオブジェクトシステムのサポートが挙げられる。
これは、Qtの中核をなす機能であり、シグナル / スロットのメカニズムやプロパティシステムを可能にするものである。

Q_OBJECTマクロは、このメタオブジェクトシステムの中心的な要素である。
このマクロをクラス定義に含めることにより、そのクラスにQtのメタオブジェクト機能が追加される。
これにより、シグナル / スロットの宣言、動的なプロパティの追加、実行時型情報 (RTTI) の拡張等が可能になる。

プリプロセッサは、Q_PROPERTYマクロを使用してクラスのプロパティを宣言する機能も提供している。
これにより、Qtのプロパティシステムを利用でき、GUIデザイナーツールとの連携、QML (Qt Modeling Language) でのプロパティバインディングが容易になる。

また、Qtのプリプロセッサは、プラットフォーム依存のコードを簡単に記述できるようにする機能も備えている。
例えば、Q_OS_*マクロを使用することにより、特定のOS向けのコードを条件付きでコンパイルすることができる。

さらに、国際化 (i18n) のサポートも重要な機能の1つである。
QT_TR_NOOPQ_TRANSLATE_NOOP等のマクロを使用することにより、翻訳可能な文字列を簡単にマークアップすることができる。

これらの機能に加えて、Qtのプリプロセッサは、シグナル / スロットの接続を最適化するためのプライベートシグナル、メモリ管理を支援するためのスマートポインタマクロ等、
様々な便利な機能を提供している。

Qtのプリプロセッサは、moc (Meta-Object Compiler) と呼ばれるツールと密接に連携している。
mocは、Qtのマクロを含むヘッダファイルを解析して、必要なメタオブジェクトコードを生成する。

このプロセスは、一般的に、ビルドシステムにより自動的に処理されるため、開発者は特別な操作を行う必要はない。


QT_VERSION_CHECKマクロ

QT_VERSION_CHECKマクロを使用する場合は、QtGlobalをインクルードする必要がある。
このヘッダファイルには、QT_VERSION_CHECKマクロを含む多くのQtの基本的な定義が含まれている。

 #include <QtGlobal>



クラスに関するマクロ

Q_OBJECT

Qtのメタオブジェクトシステムの中核となるマクロである。
QObjectクラスを継承するサブクラスの定義内で使用され、シグナル / スロットのメカニズム、実行時型情報 (RTTI)、動的プロパティシステムを有効にする。

このマクロを使用することにより、クラスはQtの多くの高度な機能を使用できるようになる。

Q_PROPERTY

クラスのプロパティを宣言するために使用する。

このマクロを使用することにより、C++のメンバ変数をQtのプロパティシステムに統合できる。
これにより、QMLでのプロパティバインディングやGUIデザイナーでのプロパティ編集が可能になる。

また、プロパティの読み取り / 書き込みメソッド、通知シグナル、リセットメソッド等も定義できる。

 class Person : public QObject
 {
    Q_OBJECT
    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
    Q_PROPERTY(int age READ age WRITE setAge NOTIFY ageChanged)
 
 private:
    QString m_name;
    int m_age = 0;
 
 public:
    Person(QObject *parent = nullptr) : QObject(parent) {}
 
    QString name() const { return m_name; }
 
    void setName(const QString &name)
    {
       if (m_name != name) {
          m_name = name;
          emit nameChanged(m_name);
       }
    }
 
    int age() const { return m_age; }
 
    void setAge(int age)
    {
       if (m_age != age) {
          m_age = age;
          emit ageChanged(m_age);
       }
    }
 
 signals:
    void nameChanged(const QString &name);
    void ageChanged(int age);
 };


Q_INVOKABLE

このマクロをメソッド宣言の前に付加することにより、そのメソッドをQMLから呼び出し可能にする。

一般的に、publicスロットは自動的にQMLから呼び出せるが、publicメソッドはQ_INVOKABLEを使用しない限り呼び出せない。

signals / Q_SIGNAL / Q_SIGNALS

シグナルを宣言するために使用する。

シグナルは、オブジェクト間の通信メカニズムの一部であり、特定のイベントが発生したことを他のオブジェクトに通知するために使用する。

slots / Q_SLOT / Q_SLOTS

スロットを宣言するために使用する。

スロットはシグナルに接続可能な特殊な関数であり、シグナルが発信されたときに呼び出される。

Q_EMIT

シグナルを発信 (emit) する場合に使用するマクロである。 本質的には、C++のソースコード内でシグナルを発信するための構文的な装飾である。

シグナルを発信する場合は、明示的にそれがシグナルの発信であることを示す。 通常は、emitキーワードとして使用するが、Q_EMITはその完全修飾名である。 コンパイル時には何も行わず、コードの可読性を向上させる目的で使用する。

 class MyClass : public QObject
 {
    Q_OBJECT
 
 signals:
    void valueChanged(int newValue);
 
 public:
    void updateValue(int value)
    {
        Q_EMIT valueChanged(value);
        // または、emit valueChanged(value); としてもよい
    }
 };


Q_GADGET

QObjectクラスを継承せずに、Qtのメタオブジェクトシステムの一部の機能 (プロパティ、列挙型等) を利用可能にするマクロである。

軽量なオブジェクトを作成する場合に有効である。

 class Point
 {
    Q_GADGET
    Q_PROPERTY(int x MEMBER m_x)
    Q_PROPERTY(int y MEMBER m_y)
 
 private:
    int m_x,
        m_y;
 
 public:
    Point(int x = 0, int y = 0) : m_x(x), m_y(y) {}

    int x() const { return m_x; }
    int y() const { return m_y; }
 };
 
 Q_DECLARE_METATYPE(Point)


Q_ENUMマクロ

列挙型をQtのメタオブジェクトシステムに登録するために使用する。
これにより、列挙型の値を文字列に変換する、または、QMLで使用したりすることが可能になる。

 class TrafficLight : public QObject
 {
    Q_OBJECT
 
 private:
    Color m_color = Color::Red;
 
 public:
    enum class Color {
       Red,
       Yellow,
       Green
    };
 
    Q_ENUM(Color)
 
    TrafficLight(QObject *parent = nullptr) : QObject(parent) {}
 
    void setColor(Color color)
    {
       m_color = color;
       qDebug() << "Color set to:" << QMetaEnum::fromType<Color>().valueToKey(static_cast<int>(m_color));
    }
 };


Q_ENUMSマクロ (Qt 5のみ)

列挙型をQtのメタオブジェクトシステムに登録するために使用する。

複数の列挙型を1度に登録することができる。
列挙型の値を文字列に変換する、または、その逆を行うことが可能である。

また、QMLで列挙型を使用可能にする。

ただし、Qt 6以降では、Q_ENUMマクロに置き換えられている。
後方互換性のためにサポートされている。

Q_DISABLE_COPY / Q_DISABLE_MOVE

Q_DISABLE_COPYマクロは、クラスのコピーコンストラクタとコピー代入演算子を削除する。
これにより、クラスのインスタンスが誤ってコピーされることを防ぐ。

Q_DISABLE_MOVEマクロは、クラスのムーブコンストラクタとムーブ代入演算子を削除する。
これにより、クラスのインスタンスが移動されることを防ぐ。

これらのマクロは、以下に示すようなメリットがある。

  • オブジェクトの意図しない複製や移動を防ぐことができる。
  • リソースの所有権に関する問題を回避できる。
  • クラスの設計意図を明確に示すことができる。


以下の例では、クラスのインスタンスがコピーや移動されることを防ぐ方法を示している。
これにより、意図しないオブジェクトの複製や移動を防ぎ、リソース管理を適切に行うことができる。

 // NonCopyable.hファイル
 
 class NonCopyable
 {
 private:
    Q_DISABLE_COPY(NonCopyable)
 
 public:
    NonCopyable()  = default;
    ~NonCopyable() = default;
 
    void doSomething() { qDebug() << "Doing something"; }
 };


 // NonMovable.hファイル
 
 class NonMovable
 {
 private:
    Q_DISABLE_MOVE(NonMovable)
 
 public:
    NonMovable()  = default;
    ~NonMovable() = default;
 
    void doSomething() { qDebug() << "Doing something"; }
 };


 // 使用例
 
 #include "NonCopyable.h"
 #include "NonMovable.h"
 
 void testNonCopyable()
 {
    NonCopyable nc1;
 
    // NonCopyable nc2 = nc1;  // コンパイルエラー: コピーコンストラクタは削除されている
    // NonCopyable nc3(nc1);   // コンパイルエラー: コピーコンストラクタは削除されている
    // nc1 = NonCopyable();    // コンパイルエラー: コピー代入演算子は削除されている
 
    nc1.doSomething();         // コンパイル可能
 }
 
 void testNonMovable()
 {
    NonMovable nm1;
 
    // NonMovable nm2 = std::move(nm1);  // コンパイルエラー: ムーブコンストラクタは削除されている
    // nm1 = NonMovable();               // コンパイルエラー: ムーブ代入演算子は削除されている
 
    nm1.doSomething();                   // コンパイル可能
 }
 
 int main()
 {
    testNonCopyable();
    testNonMovable();
 
    return 0;
 }


Q_FLAG / Q_FLAGS

列挙型をQtのメタオブジェクトシステムに登録するために使用する。
Q_FLAGマクロは単一の列挙型、Q_FLAGSマクロは複数の列挙型を登録する。

これにより、列挙型の値を文字列に変換する、または、QMLで使用することが可能になる。

 class Window : public QObject
 {
    Q_OBJECT
 
 public:
    enum Option {
       NoOption    = 0x0,
       ShowTitle   = 0x1,
       ShowButtons = 0x2
    };
    Q_FLAG(Option)
 
    enum Mode {
       Normal,
       Fullscreen
    };
    Q_ENUM(Mode)
 
    Q_FLAGS(Options, Option)
 
 public:
    Window(QObject *parent = nullptr) : QObject(parent) {}
 };


 // 使用例
 
 void useEnums()
 {
    Window window;
    QMetaEnum optionEnum = QMetaEnum::fromType<Window::Option>();
 
    qDebug() << optionEnum.valueToKey(Window::ShowTitle);  // 出力: "ShowTitle"
 }


Q_CLASSINFO

クラスに関する追加のメタデータを定義するために使用する。
これは、クラスに関する任意の名前と値のペアとして情報を格納することができ、実行時にこの情報にアクセスすることができる。

リフレクションを通じてランタイムにこの情報にアクセスすることができる。

以下の例では、MyClassに対して3つの追加情報 (Version、Author、Description) を定義している。
printClassInfoメソッドでは、QMetaObjectを使用してこれらの情報にアクセスして表示している。

 // MyClass.hファイル
 
 #include <QObject>
 #include <QMetaClassInfo>
 #include <QDebug>
 
 class MyClass : public QObject
 {
    Q_OBJECT
    Q_CLASSINFO("Version", "1.0")
    Q_CLASSINFO("Author", "John Doe")
    Q_CLASSINFO("Description", "This is a sample class")
 
 public:
    MyClass(QObject *parent = nullptr) : QObject(parent) {}
 
    static void printClassInfo()
    {
       const QMetaObject* metaObject = &MyClass::staticMetaObject;
       qDebug() << "Class name: " << metaObject->className();
 
       int count = metaObject->classInfoCount();
       qDebug() << "Class info count: " << count;
 
       for (int i = 0; i < count; ++i) {
          QMetaClassInfo classInfo = metaObject->classInfo(i);
          qDebug() << classInfo.name() << ":" << classInfo.value();
       }
    }
 };


 // main.cppファイル
 
 #include "MyClass.h"
 
 int main()
 {
    MyClass::printClassInfo();
 
    return 0;
 }


Q_DECLARE_TYPEINFO

カスタム型の特性をQtに伝えるために使用する。

主に、型がトリビアルにコピー可能かどうか、また、ポインタ型のように扱えるかどうかを指定する。
これにより、Qtのコンテナクラスが特定の型を効率的に扱えるようになる。

 struct MyPOD {
    int x;
    double y;
 };
 
 Q_DECLARE_TYPEINFO(MyPOD, Q_PRIMITIVE_TYPE);
 
 struct MyComplex {
    QString str;
    QVector<int> vec;
 };
 
 Q_DECLARE_TYPEINFO(MyComplex, Q_MOVABLE_TYPE);


Q_DECLARE_INTERFACE

抽象インターフェースクラスを宣言するために使用する。

主に、Qtのプラグインシステムで使用され、インターフェースにユニークな識別子を割り当てる。

 class MyInterface
 {
 public:
    virtual ~MyInterface() {}
    virtual void doSomething() = 0;
 };
 
 Q_DECLARE_INTERFACE(MyInterface, "com.mycompany.MyInterface")
 
 class MyPlugin : public QObject, public MyInterface
 {
    Q_OBJECT
    Q_INTERFACES(MyInterface)
 
 public:
    void doSomething() override
    {
       // 実装を記述する
    }
 };


Q_DECLARE_FLAGS / Q_DECLARE_OPERATORS_FOR_FLAGS

Q_DECLARE_FLAGSマクロは、列挙型からフラグ型を生成するために使用する。

フラグ型は、複数の列挙値をビット演算子で組み合わせて使用できるようにする。

Q_DECLARE_OPERATORS_FOR_FLAGSマクロは、Q_DECLARE_FLAGSマクロで宣言されたフラグ型に対して、ビット演算子のオーバーロードを提供する。
これにより、フラグ値を簡単に組み合わせたり操作したりすることができる。

一般的に、これら2つのマクロは同時に使用する。

 class Window : public QObject
 {
    Q_OBJECT
 
 private:
    Options m_options;
 
 public:
    enum Option {
       NoOption    = 0x0,
       ShowTitle   = 0x1,
       ShowButtons = 0x2,
       ClosableWindow = 0x4
    };
    Q_DECLARE_FLAGS(Options, Option)
 
 public:
    Window(QObject *parent = nullptr) : QObject(parent) {}
 
    void setOptions(Options options)
    {
        m_options = options;
    }
 };
 
 Q_DECLARE_OPERATORS_FOR_FLAGS(Window::Options)


 // 使用例
 int main()
 {
    Window window;
    window.setOptions(Window::ShowTitle | Window::ShowButtons);
 
    return 0;
 }


Q_DECLARE_PRIVATE / Q_DECLARE_PUBLIC

これは、Qtのプライベート実装パターンと共有データの管理に関連している。

Qtのd-pointerイディオムを実装するために使用する。
このパターンは、クラスの実装詳細を隠蔽して、バイナリ互換性を維持するのに役立つ。

また、プライベートクラスとパブリッククラス間で相互にアクセスが可能となる。

 // MyClass.hファイル
 
 #include "MyClassPrivate.h"
 
 class MyClassPrivate;
 
 class MyClass
 {
 private:
    Q_DECLARE_PRIVATE(MyClass)
    MyClassPrivate *d_ptr;
 
 public:
    MyClass() : d_ptr(new MyClassPrivate(this))
    {}
    ~MyClass()
    {
       delete d_ptr;
    }
 
    void doSomething()
    {
       Q_D(MyClass);
       d->internalFunction();
    }
 };


 // MyClassPrivate.hファイル
 
 class MyClassPrivate
 {
 public:
    MyClassPrivate(MyClass *q) : q_ptr(q) {}
 
    void MyClassPrivate::internalFunction()
    {
       Q_Q(MyClass);
 
       // publicクラスのメンバーにアクセスできる
       someData = 42;
    }
 
    MyClass *q_ptr;
    Q_DECLARE_PUBLIC(MyClass)
 
    int someData;
 };


Q_DECLARE_SHARED

暗黙的な共有 (implicit sharing) を使用するクラスを宣言するために使用する。
これにより、クラスのインスタンスを効率的にコピーできる。

これは、メモリ使用量を削減でき、大きなオブジェクトの不必要なコピーを避けることができる。

 // MySharedData.hファイル
 
 #include <QSharedData>
 #include <QSharedDataPointer>
 #include "MySharedDataPrivate.h"
 
 class MySharedDataPrivate;
 
 class MySharedData
 {
 private:
    QSharedDataPointer<MySharedDataPrivate> d;
 
 public:
    MySharedData() : d(new MySharedDataPrivate) {}
    MySharedData::MySharedData(const MySharedData &other) : d(other.d) {}
    MySharedData &operator=(const MySharedData &other)
    {
       if (this != &other)
       d = other.d;
 
       return *this;
    }
    ~MySharedData(){}
 
    void setValue(int value)
    {
       d->value = value;
    }
 
    int MySharedData::value() const
    {
       return d->value;
    }
 };
 
 // クラスの宣言に関連する情報を提供して、
 // そのクラスを使用するコードがこの情報にアクセスする必要があるため、ここで宣言する
 Q_DECLARE_SHARED(MySharedData)


 // MySharedDataPrivate.hファイル
 
 #include <QSharedData>
 
 class MySharedDataPrivate : public QSharedData
 {
 public:
    MySharedDataPrivate() : value(0) {}
    MySharedDataPrivate(const MySharedDataPrivate &other) : QSharedData(other), value(other.value) {}
 
    int value;
 };


 // 使用例
 
 void useSharedData()
 {
    MySharedData data1;
    data1.setValue(42);
 
    MySharedData data2 = data1;  // データは共有される
    data2.setValue(100);         // この時点で、データのコピーが作成される
 
    qDebug() << data1.value();  // 出力: 42
    qDebug() << data2.value();  // 出力: 100
 }


Q_D / Q_Q

d-pointerイディオムの実装時において、privateクラスとpublicクラス間のアクセスを容易にする。

Q_Dマクロは、publicクラスからprivateクラスにアクセスするために使用する。
Q_Qマクロは、privateクラスからpublicクラスにアクセスするために使用する。

これらのマクロを使用することにより、以下に示すようなメリットがある。

  • private実装とpublicインターフェース間のアクセスを簡潔に記述することができる。
  • タイプセーフなアクセスが可能になる。
  • ソースコードの可読性が向上する。


以下の例では、publicクラスとprivateクラス間で相互にアクセスする方法を示している。
これにより、実装の詳細を隠蔽しつつ、必要な場合に内部データにアクセスすることができる。

 // MyClass.hファイル
 
 #include "MyClassPrivate.h"
 
 class MyClassPrivate;
 
 class MyClass
 {
 private:
    Q_DECLARE_PRIVATE(MyClass)
    MyClassPrivate *d_ptr;
 
 public:
    MyClass() : d_ptr(new MyClassPrivate(this)) {}
    ~MyClass()
    {
       delete d_ptr;
    }
 
    void publicMethod()
    {
       Q_D(MyClass);  // d は MyClassPrivate* 型
       d->privateMethod();
       qDebug() << "Public method called, someData:" << d->someData;
    }
 };


 // MyClassPrivate.hファイル
 
 class MyClassPrivate
 {
 public:
    MyClassPrivate(MyClass *q) : q_ptr(q) {}

    void privateMethod()
    {
       Q_Q(MyClass);  // qはMyClass*型
       someData = 42;
       qDebug() << "Private method called by" << q;
    }

    MyClass *q_ptr;
    Q_DECLARE_PUBLIC(MyClass)

    int someData;
 };



型に関するマクロ

Q_DECLARE_METATYPE

カスタム型をQVariantクラスで使用可能にするためのマクロである。
これにより、その型をQVariantクラスに格納したり、シグナル / スロットシステムで使用することができる。

 struct CustomData
 {
    int     id;
    QString name;
 };
 
 Q_DECLARE_METATYPE(CustomData)
 
 // 使用例
 void useCustomData()
 {
    CustomData data{1, "Example"};
    QVariant variant = QVariant::fromValue(data);
 
    if (variant.canConvert<CustomData>()) {
       CustomData retrievedData = variant.value<CustomData>();
       qDebug() << "ID:" << retrievedData.id << "Name:" << retrievedData.name;
    }
 }



翻訳に関するマクロ

QT_TR_NOOP

国際化 (i18n) のために使用する。

このマクロで囲まれた文字列は、翻訳ツールによって抽出可能になるが、実行時には通常の文字列として扱われる。
つまり、QT_TR_NOOPマクロは、文字列を直接翻訳せずに、後でtrメソッドを使用して翻訳できるようにするために使用する。

実際に翻訳を行う場合は、QObject::trメソッド (現在のロケールに基づいて適切な翻訳を返す) を使用する。

以下の例では、は実際の翻訳ファイル(.qmファイル)をロードするため、QTranslatorクラスを使用している。
InternationalWidget::showMessagesメソッドを実行して、翻訳されたメッセージを表示している。

 // InternationalWidget.hファイル
 
 #include <QCoreApplication>
 #include <QTranslator>
 #include <QLocale>
 #include <QDebug>
 
 class InternationalWidget : public QObject
 {
    Q_OBJECT
 
 public:
    InternationalWidget(QObject *parent = nullptr) : QObject(parent) {}
 
    void showMessages()
    {
       // QT_TR_NOOPを使用して、翻訳が必要な文字列を標識付けします
       const char* message1 = QT_TR_NOOP("Hello, World!");
       const char* message2 = QT_TR_NOOP("Welcome to Qt!");
       const char* message3 = QT_TR_NOOP("Goodbye!");
 
       // 実際に翻訳を行う際は、QObject::tr()を使用します
       qDebug() << "Translated messages:";
       qDebug() << tr(message1);
       qDebug() << tr(message2);
       qDebug() << tr(message3);
    }
 };


 // main.cppファイル
 
 #include "InternationalWidget.h"
 
 int main(int argc, char *argv[])
 {
    QCoreApplication app(argc, argv);
 
    // トランスレータを設定 (実際には、翻訳ファイルが必要)
    QTranslator translator;
    if (translator.load(QLocale(), QLatin1String("myapp"), QLatin1String("_"), QLatin1String(":/translations"))) {
        QCoreApplication::installTranslator(&translator);
    }
 
    InternationalWidget widget;
    widget.showMessages();
 
    return app.exec();
 }


Q_TRANSLATE_NOOP

国際化 (i18n) のために使用するマクロである。
翻訳が必要な文字列を標識付けするために使用するが、その場では翻訳を行わない。

文字列を翻訳ツールで認識可能にするが、実行時には元の文字列をそのまま返す。
後で翻訳が必要になる可能性のある文字列を準備する場合に使用する。

一般的に、QObject::trメソッドやQCoreApplication::translateメソッドと組み合わせて使用する。

以下の例では、"File not found"という文字列が翻訳ツールにより抽出可能になるが、変数messageには元の英語の文字列がそのまま格納されている。
後で必要に応じて、QCoreApplication::translateメソッドを使用して実際の翻訳を行う。

 const char *message = Q_TRANSLATE_NOOP("MyDialog", "File not found");
 
 // 後で翻訳する場合
 QString translatedMessage = QCoreApplication::translate("MyDialog", message);



Q_ARGマクロ

Q_ARGマクロは、Qtフレームワークで提供されているマクロの1つであり、主にQMetaObject::invokeMethodメソッドと組み合わせて使用される。
このマクロの主な目的は、メタオブジェクトシステムを介してメソッドを呼び出す時に、引数の型と値を指定することである。

Q_ARGマクロのシンタックスを以下に示す。

 // <引数の型>は、C++の型 (int型, QStringクラス, QVariantクラス等)
 // <値>は、その型の具体的な値である
 
 Q_ARG(<引数の型>, <>)


Q_ARGマクロは、スレッド間通信やイベントループを介したメソッド呼び出し等、直接的なメソッド呼び出しが難しい場合に特に有効である。
例えば、あるスレッドから別のスレッドにあるオブジェクトのメソッドを呼び出す場合等に使用される。

以下の例では、someObjectオブジェクトのupdateValueメソッド (int型とQStringクラスの2つの引数を持つ) を呼び出している。
Q_ARGマクロを使用して、このメソッドの引数の型と値を指定している。

 QMetaObject::invokeMethod(someObject, "updateValue", 
                           Qt::QueuedConnection,
                           Q_ARG(int, 42),
                           Q_ARG(QString, "Hello"));


Q_ARGマクロのメリットを以下に示す。

  • 型安全性
    コンパイル時に引数の型チェックが行われるため、誤った型の引数を渡すことによるランタイムエラーを防ぐことができる。
  • 可変個数の引数を持つメソッドの呼び出しに対応
    必要な数だけQ_ARGマクロを追加することにより、任意の数の引数を持つメソッドを呼び出すことができる。


ただし、Q_ARGマクロは、ポインタ型や参照型の引数を直接扱うことはできない。
ポインタ型や参照型の引数を使用する場合は、QVariantクラスを介して渡す必要がある。

Q_ARGマクロは、Qtのシグナル / スロットシステムと密接に関連しており、Qtプログラミングにおいて柔軟なメソッド呼び出しを実現するための重要なツールの1つである。


プラットフォームに関するマクロ

  • Q_OS_WINDOWS
  • Q_OS_LINUX
  • Q_OS_MACOS
  • Q_OS_IOS
  • Q_OS_ANDROID


上記のマクロは、特定のOS向けのコードを条件付きでコンパイルするために使用する。
OS固有の機能や最適化を実装する場合に、ソースコードの可読性を保ちながら異なるOS向けの処理を記述することができる。

使用例としては、以下に示すようなケースが考えられる。

  • ファイルシステムのパス区切り文字の違いに対応する。
  • OS固有のAPIを使用する。
  • GUIの外観や振る舞いをプラットフォームに合わせて調整する。
  • デバイス固有の機能 (例: iOSやAndroidのセンサ) にアクセスする。


 // PlatformSpecificWidget.hファイル
 
 #include <QApplication>
 #include <QWidget>
 #include <QPushButton>
 #include <QVBoxLayout>
 #include <QDebug>
 
 class PlatformSpecificWidget : public QWidget
 {
 public:
    PlatformSpecificWidget(QWidget *parent = nullptr) : QWidget(parent)
    {
       QVBoxLayout *layout = new QVBoxLayout(this);
 
       QPushButton *button = new QPushButton("Click me", this);
       layout->addWidget(button);
 
       connect(button, &QPushButton::clicked, this, &PlatformSpecificWidget::onButtonClicked);
    }
 
 private slots:
    void onButtonClicked()
    {
       #if defined(Q_OS_WINDOWS)
          qDebug() << "Hello from Windows!";
          // Windows固有のAPI呼び出し等を記述
       #elif defined(Q_OS_LINUX)
          qDebug() << "Hello from Linux!";
          // Linux固有の処理を記述
       #elif defined(Q_OS_MACOS)
          qDebug() << "Hello from macOS!";
          // MacOS固有の処理を記述
       #elif defined(Q_OS_IOS)
          qDebug() << "Hello from iOS!";
          // iOS固有の処理を記述
       #elif defined(Q_OS_ANDROID)
          qDebug() << "Hello from Android!";
          // Android固有の処理を記述
       #else
          qDebug() << "Hello from an unknown platform!";
       #endif
 
       // プラットフォーム共通の処理
       qDebug() << "This code runs on all platforms.";
    }
 };


 // main.cppファイル
 
 #include "PlatformSpecificWidget.h"
 
 int main(int argc, char *argv[])
 {
    QApplication app(argc, argv);
 
    PlatformSpecificWidget widget;
    widget.show();
 
    return app.exec();
 }