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
};
コンシューマー コードは、CString
と CMyString
の組み合わせを使用します。 "MyString.h" がプリコンパイル済みヘッダーに含まれておらず、CString
の使用方法によっては、CMyString
が表示されないことがあります。
CString
および CMyString
クラスを別々のソースファイル (Source1.cpp と Source2.cpp) で使用するとします。 Source1.cpp では、CMyString
と #include MyString.h を使用します。 Source2.cpp では、CString
を使用しますが、#include MyString.h は使用しません。 この場合、リンカーにより CStringT
が多重定義されていることが通知されます。 これは、CString
が CMyString
をエクスポートする DLL からインポートされ、CStringT
テンプレートを使用してコンパイラによってローカルでインスタンス化されることによって起こります。
この問題を解決するには、次の操作を行います。
CStringA
と CStringW
(および必要な基本クラス) を MFC90.DLL からエクスポートします。 MFC を含むプロジェクトでは、以前の MFC の実装のように、CStringA
および CStringW
でエクスポートされた MFC DLL が常に使用されます。
次に、 CStringT
テンプレートを使用してエクスポート可能な派生クラス CStringT_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 で、前の CString
、CStringA
、CStringW
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
基底クラスに転送する場合に限定されます。CString
、CStringA
、CStringW
は、MFC 共有 DLL をビルドする場合にのみ__declspec(dllexport/dllimport)
とマークされる必要があります。 MFC スタティック ライブラリとリンクする場合は、これらのクラスをエクスポート済みとしてマークしないでください。そうしないと、ユーザー DLL 内のCString
、CStringA
、CStringW
の内部使用による場合もCString
がエクスポート済みとしてマークされます。