38

dll/共有オブジェクトで配布されるC++ライブラリのAPIを設計しています。ライブラリには、仮想関数を備えたポリモーリッククラスが含まれています。これらの仮想関数をDLLAPIで公開すると、以前のバージョンのライブラリ用に構築されたアプリケーションとのバイナリ互換性を損なうことなく、同じクラスをより多くの仮想関数で拡張できる可能性がなくなるのではないかと心配しています。

1つのオプションは、PImplイディオムを使用して仮想関数を持つすべてのクラスを非表示にすることですが、これにも制限があるようです。このように、アプリケーションはライブラリのクラスをサブクラス化し、仮想メソッドをオーバーライドする可能性を失います。

後方バイナリ互換性を維持しながら、新しいバージョンのdllで(抽象ではない)仮想メソッドを使用してAPIを拡張する可能性を失うことなく、アプリケーションでサブクラス化できるAPIクラスをどのように設計しますか?

更新:ライブラリのターゲットプラットフォームは、windows/msvcおよびlinux/gccです。

4

5 に答える 5

36

数ヶ月前、私は「GNU/Linux システム上の C++ で実装された共有ライブラリのバイナリ互換性」[ pdf ] という記事を書きました。Windows システムの概念は似ていますが、まったく同じではないことは確かです。しかし、この記事を読めば、互換性に関係する C++ バイナリ レベルで何が起こっているかがわかります。

ところで、GCC アプリケーション バイナリ インターフェイスは、標準ドキュメント ドラフト " Itanium ABI " にまとめられているため、選択したコーディング標準の正式な根拠が得られます。

簡単な例として、GCC では、他のクラスがそれを継承していない場合、より多くの仮想関数でクラスを拡張できます。ルールのより良いセットについては、記事をお読みください。

とにかく、ルールは複雑すぎて理解できない場合があります。そのため、特定の 2 つのバージョンの互換性を検証するツール、Linux 用の abi-compliance-checkerに興味があるかもしれません。

于 2009-11-21T10:13:45.937 に答える
11

KDE ナレッジ ベースには、ライブラリを作成する際にバイナリ互換性を目指す場合のすべきこととすべきでないことを説明した興味深い記事があります: Policies/Binary Compatibility Issues With C++

于 2009-11-21T12:56:27.427 に答える
1

サブクラス化の問題を誤解していると思います。

これがあなたのにきびです:

// .h
class Derived
{
public:
  virtual void test1();
  virtual void test2();
private;
  Impl* m_impl;
};

// .cpp
struct Impl: public Base
{
  virtual void test1(); // override Base::test1()
  virtual void test2(); // override Base::test2()

  // data members
};

void Derived::test1() { m_impl->test1(); }
void Derived::test2() { m_impl->test2(); }

見る ?の仮想メソッドをオーバーライドすることに問題はありません。Derivedから派生したメソッドがそれらを書き換えることができることを知るために、それらを で再宣言することを確認する必要があります (そうする場合のみ、ちなみに、これは for を提供する優れた方法ですBase) 。それを欠いている人)、そしてあなたはまだバージョンを呼び出すかもしれないあなた自身のためにそれを再定義するかもしれません.virtualDerivedfinalImplBase

そこは問題ありませんPimpl

一方で、厄介なポリモーフィズムが失われます。ポリモーフィズムが必要なのか、単なる合成が必要なのかを決めるのはあなた次第です。

于 2009-11-21T18:49:12.943 に答える
1

C++ バイナリ互換は、継承がなくても一般的に困難です。たとえば、GCC を見てください。過去 10 年間に、ABI に重大な変更が加えられた回数はわかりません。次に、MSVCには異なる一連の規則があるため、GCCとのリンクやその逆はできません...これをCの世界と比較すると、コンパイラの相互運用はそこで少し優れているようです.

Windows を使用している場合は、COM を確認する必要があります。新しい機能を導入すると、インターフェイスを追加できます。その後、呼び出し元はQueryInterface()新しい機能を新しいものに公開することができます。多くのことを変更することになったとしても、古い実装をそこに残すか、古いインターフェイスの shim を記述することができます。

于 2009-11-21T08:56:00.727 に答える