CStringT を使用した文字列クラスのエクスポート

以前は、MFC 開発者は、独自の文字列クラスを CString から派生させて特殊化していました。 Microsoft Visual C++.NET (MFC 8.0) では、CStringクラスが CStringT と呼ばれるテンプレート クラスに置き換えられました。 これにはいくつかの利点があります。

  • これにより、MFC CString クラスをより大きな MFC スタティック ライブラリまたは DLL でリンクさせることなく ATL プロジェクトで使用できるようになりました。

  • 新しい CStringT テンプレート クラスを使用すると、C++ 標準ライブラリのテンプレートと同様に、文字の特徴を指定するテンプレート パラメーターを使用して CString 動作をカスタマイズできます。

  • CStringT を使用して DLL から独自の文字列クラスをエクスポートする場合、コンパイラによって CString 基本クラスも自動的にエクスポートされます。 CString はそれ自体がテンプレート クラスであるため、コンパイラで CString が DLL からインポートされたことが認識されない限り、使用時にコンパイラによってインスタンス化される場合があります。 Visual C++ 6.0 から Visual C++ .NET にプロジェクトを移行した場合、DLL およびローカルでインスタンス化されたバージョンからインポートされた CString の競合が原因で、多重定義された CString のリンカー シンボル エラーが発生することがあります。 これを行うための適切な方法を以下に示します。

次のシナリオでは、多重定義されたクラスのシンボル エラーがリンカーによって生成されます。 CString 派生クラス (CMyString) を MFC 拡張 DLL からエクスポートするとします。

// MyString.h
class AFX_EXT_CLASS CMyString : public CString
{
   // Your implementation code
};

コンシューマー コードは、CStringCMyString の組み合わせを使用します。 "MyString.h" がプリコンパイル済みヘッダーに含まれておらず、CString の使用方法によっては、CMyString が表示されないことがあります。

CString および CMyString クラスを別々のソースファイル (Source1.cpp と Source2.cpp) で使用するとします。 Source1.cpp では、CMyString と #include MyString.h を使用します。 Source2.cpp では、CString を使用しますが、#include MyString.h は使用しません。 この場合、リンカーにより CStringT が多重定義されていることが通知されます。 これは、CStringCMyString をエクスポートする DLL からインポートされ、CStringT テンプレートを使用してコンパイラによってローカルでインスタンス化されることによって起こります。

この問題を解決するには、次の操作を行います。

CStringACStringW (および必要な基本クラス) を MFC90.DLL からエクスポートします。 MFC を含むプロジェクトでは、以前の MFC の実装のように、CStringA および CStringW でエクスポートされた MFC DLL が常に使用されます。

次に、テンプレートを使用してエクスポート可能な派生クラスをCStringTCStringT_Exported作成します。次に例を示します。

#ifdef _AFXDLL
   #define AFX_EXT_CSTRING AFX_EXT_CLASS
#else
   #define AFX_EXT_CSTRING
#endif

template< typename BaseType, class StringTraits >
class AFX_EXT_CSTRING CStringT_Exported 
   : public CStringT< BaseType, StringTraits >
{
   // Reimplement all CStringT<> constructors and
   // forward to the base class implementation
};

AfxStr.h で、前の CStringCStringACStringW typedef を次のように置き換えます。

typedef CStringT_Exported< wchar_t, 
      StrTraitMFC< wchar_t > > CStringW;

typedef CStringT_Exported< char,
      StrTraitMFC< char > > CStringA;

typedef CStringT_Exported< TCHAR,
      StrTraitMFC< TCHAR > > CString;

いくつかの注意点があります。

  • ATL 専用プロジェクトによって特殊化された CStringT クラスがエクスポートされるため、CStringT 自体をエクスポートしないでください。

  • CStringT からエクスポート可能な派生クラスを使用すると、CStringT 機能を再実装する必要が最小限に抑えられます。 追加のコードは、コンストラクターを CStringT 基底クラスに転送する場合に限定されます。

  • CStringCStringACStringW は、MFC 共有 DLL をビルドする場合にのみ __declspec(dllexport/dllimport) とマークされる必要があります。 MFC スタティック ライブラリとリンクする場合は、これらのクラスをエクスポート済みとしてマークしないでください。そうしないと、ユーザー DLL 内の CStringCStringACStringW の内部使用による場合も CString がエクスポート済みとしてマークされます。

CStringT クラス

関連項目

CStringT の使用
CString の使用