0

プロバイダーをもう少し明確に編集しました。皆様を混乱させて申し訳ありません。

これは Windows の下にあります。

pimpl イディオムを使用してクラスを実装する静的ライブラリがあります。pimpl ヘッダーは、消費するコードによって使用されるだけでなく、静的ライブラリにもリンクされます。それでも、消費コード (.exe) をコンパイルすると、リンカは、pimpl ヘッダーが隠していると思われる実装クラスの未解決の外部オブジェクトについて不平を言います。

これはどのように可能ですか?

// Foo.lib

// Foo.h

class FooImpl;

class Foo
{
    std::shared_ptr<FooImpl> pimpl_;    
public:
    Foo();
};

// Foo.cpp

#include "Foo.h"
#include "FooImpl.h"

Foo::Foo() : pimpl_(new FooImpl())
{
}

// This is how its used in Bar.exe
// Bar.exe links against Foo.lib

// Bar.h

#include "Foo.h"

class Bar
{
    Foo access_foo_;
};

// Bar.cpp

#include "Bar.h"

Bar.exe をコンパイル/リンクすると、リンカは FooImpl を解決できないと文句を言います。今は仕事用の PC にアクセスできないので、正確に何を言っているのか忘れてしまいましたが、それが要点です。pimpl ルートに進む目的は、Bar.exe が FooImpl を気にする必要がないようにすることだったので、このエラーは私には意味がありませんでした。

正確なエラーは次のようになります。

1>Foo.lib(Foo.obj): エラー LNK2019: 未解決の外部シンボル "public: __thiscall FooImpl::FooImpl(void)" (??0FooImpl@@QAE@XZ) が関数 "public: __thiscall Foo::Foo で参照されています(無効)" (??0Foo@@QAE@XZ)

4

2 に答える 2

2

1>Foo.lib(Foo.obj): エラー LNK2019: 未解決の外部シンボル "public: __thiscall FooImpl::FooImpl(void)" (??0FooImpl@@QAE@XZ) が関数 "public: __thiscall Foo::Foo で参照されています(無効)" (??0Foo@@QAE@XZ)

リンカーは、 の定義が見つからないと不平を言っていますFooImpl::FooImpl()。ここでコンストラクターを呼び出しています-

Foo::Foo() : pimpl_(new FooImpl())
                    // ^^^^^^^^^ Invoking the default constructor.

デフォルトコンストラクタの宣言を提供しましたが、定義ではありません。

于 2011-09-30T23:35:43.547 に答える
2

スタティック ライブラリを作成すると、リンカは不足しているすべてのものを解決しようとはしません。後で別のライブラリにリンクするか、実行可能ファイル自体が不足している機能に寄与することを前提としています。ライブラリ プロジェクトに重要な実装ファイルを含めるのを忘れているに違いありません。

もう 1 つの可能性は、pimpl 実装クラスがテンプレート クラスであるということです。テンプレートはすぐにはコードを生成しません。コンパイラは、テンプレート パラメーターが入力された状態でテンプレートを使用しようとするまで待機します。実装ファイルには、ライブラリでサポートされるパラメーターを含むテンプレートのインスタンス化が含まれている必要があります。


あなたの編集を見た後、問題は Foo::Foo コンストラクターが FooImpl::FooImpl コンストラクターにアクセスする必要があるが、リンカーはそれを見つける場所を知らないということです。リンカーがライブラリをまとめるとき、その時点ですべての参照を解決しようとはしません。これは、さらに別のライブラリに依存している可能性があるためです。すべてを解決する必要があるのは、実行可能ファイルをまとめるときだけです。したがって、Bar は FooImpl について直接知る必要はありませんが、それでも依存関係があります。

これは 2 つの方法のいずれかで解決できます。ライブラリから Foo と一緒に FooImpl をエクスポートするか、Foo の前に FooImpl を配置して両方を Foo.cpp に配置して、コンパイル時に Foo が FooImpl にアクセスできるようにします。

于 2011-09-30T21:47:45.457 に答える