以前は、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がエクスポート済みとしてマークされます。