2

CRTP パターンを使用して、他のクラスが派生するインターフェイスを作成しています。

インターフェイスでは、構造体を前方宣言します (インターフェイスに他のものをドラッグしたくないので重要です) が、インターフェイスを定義する cpp ファイルにその定義を含めます。

Interface.h

#ifndef INTERFACE_H_INCLUDED
#define INTERFACE_H_INCLUDED

// forward declaration
class ForwardDecl;

template <class Derived>
class Interface
{
public:
    ForwardDecl interfaceMethod();

};

#endif // INTERFACE_H_INCLUDED

ForwardDecl.h

#ifndef FORWARDDECL_H_INCLUDED
#define FORWARDDECL_H_INCLUDED

struct ForwardDecl
{
    ForwardDecl(int i):internal(i)
    {}

    int internal;
};

#endif // FORWARDDECL_H_INCLUDED

インターフェイス.cpp

#include "Interface.h"
#include "ForwardDecl.h"

template<class Derived>
ForwardDecl Interface<Derived>::interfaceMethod()
{
    return static_cast<Derived *>(this)->implementation_func();
}

そして、これはインターフェースを実装する実装です

実装.h

#ifndef IMPLEMENTATION_H_INCLUDED
#define IMPLEMENTATION_H_INCLUDED
#include "Interface.h"
class ForwardDecl;

class Implementation: public Interface<Implementation>
{
    friend class Interface<Implementation>;
private:
    ForwardDecl implementation_func();

};


#endif // IMPLEMENTATION_H_INCLUDED

実装.cpp

#include "Implementation.h"
#include "ForwardDecl.h"
#include <iostream>
struct ForwardDecl Implementation::implementation_func()
{
    ForwardDecl fd(42);
    std::cout << fd.internal << std::endl;

    return fd;
}

そしてメインファイル

#include <iostream>
#include "Implementation.h"
#include "ForwardDecl.h"
using namespace std;

int main()
{
    Implementation impl;

    ForwardDecl fd = impl.interfaceMethod();
    cout << fd.internal << endl;
    return 0;
}

VS と GCC の両方でリンク エラーが発生します。

回避策はありますか?ありがとうございました。

4

2 に答える 2

1

関数テンプレートとクラス テンプレートのメンバー関数の定義は、それらのテンプレートをインスタンス化するすべての翻訳単位で表示される必要があります。つまり、テンプレート定義をファイルに入れるべきではありません。つまり、 の内容を.cppに移動する必要があります。Interface.cppInterface.h

于 2013-04-08T13:30:56.493 に答える
1

非常にアプローチに欠陥があります: ForwardDecl インスタンスを返すパブリック関数があるため、この関数を使用するすべてのクライアントには、その型の定義を含める必要があります。これは、その型を最初から公開できることを意味します。これには、関数定義をインラインにすることが含まれます。これにより、リンカーの問題が修正されます。

ただし、その構造体の内容を本当に隠したい場合で、クライアントがそれを直接必要としないことが確実な場合は、それを宣言してから、そのような構造体への参照を渡すことができます (またはポインターですが、生のポインターは悪ですが、 #マクロと同じ悪のリーグ)。その場合でも、関数定義をインラインにします。

関数をインライン化したくない場合は、必要な型の関数テンプレートを明示的にインスタンス化することもできます。テンプレートの .cpp ファイルの最後に次のようなものを追加しますtemplate class Interface<int>;(正確な構文は覚えていないので、フルール ド セルのいくつかのフレークを使用してください。詳細については、parashift.com の C++ FAQ を参照してください)。ただし、これにより、テンプレートを使用するすべてのタイプの調整が必要になるため、テンプレートの汎用性が少し低下しますが、まれなケースではアプローチになる可能性があります。

于 2013-04-08T21:07:55.977 に答える