「Qtの基礎 - ライブラリ」の版間の差分

ナビゲーションに移動 検索に移動
238行目: 238行目:
<br><br>
<br><br>


== ライブラリとバイナリ互換性 ===
== ライブラリとバイナリ互換性 ==
==== バイナリ互換性とは ====
==== バイナリ互換性とは ====
大規模なソフトウェアの場合、複数の機能を再利用したり、プラグイン等を開発するためにライブラリを使用することが多い。<br>
大規模なソフトウェアの場合、複数の機能を再利用したり、プラグイン等を開発するためにライブラリを使用することが多い。<br>
247行目: 247行目:
バイナリ互換性とは、ライブラリとそれをリンクしたソフトウェアの間に互換性があるかということである。<br>
バイナリ互換性とは、ライブラリとそれをリンクしたソフトウェアの間に互換性があるかということである。<br>
例えば、以下のようなライブラリを開発したとする。<br>
例えば、以下のようなライブラリを開発したとする。<br>
<syntaxhighlight lang="c++">
// Plugin_global.h
#ifndef PLUGIN_GLOBAL_H
#define PLUGIN_GLOBAL_H
#include <QtCore/qglobal.h>
#ifdef Q_OS_WIN  // Windows
    #if defined(PLUGIN_LIBRARY)
      #define PLUGIN_EXPORT __declspec(dllexport)
    #else
      #define PLUGIN_EXPORT
    #endif
#elif Q_OS_LINUX  // Linux
    #if defined(PLUGIN_LIBRARY)
      #define PLUGIN_EXPORT Q_DECL_EXPORT
    #else
      #define PLUGIN_EXPORT Q_DECL_IMPORT
    #endif
#endif
#endif // PLUGIN_GLOBAL_H
</syntaxhighlight>
<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
  // Plugin.h
  // Plugin.h
   
   
  class Plugin
#ifndef PLUGIN_H
#define PLUGIN_H
#include "Plugin_global.h"
  class PLUGIN_EXPORT Plugin
  {
  {
  public:
  public:
     Plugin(){}
     Plugin();
     ~Plugin(){}
     virtual ~Plugin();
   
   
  private:
  private:
     int version;
     int version;
  };
  };
#endif // PLUGIN_H
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<br>
<syntaxhighlight lang="c++">
// Plugin.cpp
#include "Plugin.h"
Plugin::Plugin()
{
}
Plugin::~Plugin()
{
}
</syntaxhighlight>
以下に、上記のライブラリをリンクするソフトウェアを記述する。<br>
以下に、上記のライブラリをリンクするソフトウェアを記述する。<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
299行目: 344行目:
 
 
     return 0;
     return 0;
}
</syntaxhighlight>
<br>
次に、以下の例のように、ライブラリの機能を追加したとする。<br>
機能を追加したライブラリを生成して、それを利用側のソフトウェアに再リンクする時、エラーを出力してクラッシュする。
(利用側のソフトウェアも再ビルドする場合は、正常に読み込まれる)
これは、派生クラスのメモリレイアウトが変更されたからである。
(クラスの機能を追加することにより、メンバ変数またはメンバ関数のオフセット値が変更される)
<syntaxhighlight lang="c++">
// Plugin.h
#ifndef PLUGIN_H
#define PLUGIN_H
#include "Plugin_global.h"
#include <string>
class PLUGIN_EXPORT Plugin
{
public:
    Plugin();
    virtual ~Plugin();
private:
    int version;
    std::string author;
};
#endif  // PLUGIN_H
</syntaxhighlight>
<br>
==== バイナリ互換性を保つ方法 ====
バイナリ互換性を保つ方法として、Pimplイディオムを使用する。<br>
Pimplは、元々プライベートの実装を隠蔽するために使用されるイディオムである。<br>
<br>
バイナリ互換性を保つためにPimplを使用する理由として、<br>
変数を1つのクラスにまとめて、後からソースコードを変更してもオフセット値が変化しない利点がある。<br>
<br>
以下の例では、Implクラスを使用することで、Pluginクラスに存在したプライベートメンバの実装をまとめて隠蔽している。<br>
このように、メンバ変数およびメンバ関数を他クラス(ここでは、Implクラス)にまとめて記述することで、<br>
後から変更があってもクラッシュすることは無い。<br>
<br>
これが、Pimplを使用したバイナリ互換性の保ち方である。<br>
<syntaxhighlight lang="c++">
// Impl.h
#ifndef IMPL_H
#define IMPL_H
#include <string>
class Impl
{
public:
    int version;
    std::string author;
};
#endif  // IMPL_H
</syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
// Plugin_global.h
#ifndef PLUGIN_GLOBAL_H
#define PLUGIN_GLOBAL_H
#include <QtCore/qglobal.h>
#ifdef Q_OS_WIN  // Windows
    #if defined(PLUGIN_LIBRARY)
      #define PLUGIN_EXPORT __declspec(dllexport)
    #else
      #define PLUGIN_EXPORT
    #endif
#elif Q_OS_LINUX  // Linux
    #if defined(PLUGIN_LIBRARY)
      #define PLUGIN_EXPORT Q_DECL_EXPORT
    #else
      #define PLUGIN_EXPORT Q_DECL_IMPORT
    #endif
#endif
#endif // PLUGIN_GLOBAL_H
</syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
// Plugin.h
#ifndef PLUGIN_H
#define PLUGIN_H
#include "Plugin_global.h"
#include "Impl.h"
#include <memory>
class PLUGIN_EXPORT Plugin
{
public:
    Plugin();
    virtual ~Plugin();
private:
    std::unique_ptr<Impl> pImpl;
};
#endif  // PLUGIN_H
</syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
// Plugin.cpp
#include "Plugin.h"
#include "Impl.h"
#include <memory>
Plugin::Plugin() : pImpl(std::make_unique<Impl>())
{
}
Plugin::~Plugin()
{
  }
  }
  </syntaxhighlight>
  </syntaxhighlight>

案内メニュー