Exportación de clases de cadena mediante CStringT
En el pasado, los desarrolladores de MFC han derivado de CString
para especializar sus propias clases de cadena. En Microsoft Visual C++.NET (MFC 8.0), la clase CString se reemplazó por una clase de plantilla denominada CStringT. Esto proporcionó varias ventajas:
Permitió que la clase
CString
de MFC se usara en proyectos ATL sin vincular en la biblioteca estática o DLL de MFC más grande.Con la nueva clase de plantilla
CStringT
, puede personalizar el comportamiento deCString
mediante parámetros de plantilla que especifican rasgos de caracteres, de forma similar a las plantillas de la biblioteca estándar de C++.Al exportar su propia clase de cadena desde un archivo DLL mediante
CStringT
, el compilador también exporta automáticamente la clase baseCString
. Dado queCString
es una clase de plantilla, puede crear instancias del compilador cuando se usa, a menos que el compilador tenga en cuenta queCString
se importa desde un archivo DLL. Si ha migrado proyectos de Visual C++ 6.0 a Visual C++.NET, es posible que haya visto errores de símbolo del vinculador para una multiplicación definida comoCString
debido a la colisión de la importación deCString
desde un archivo DLL y la versión de creación de instancias local. La forma adecuada de hacerlo se describe a continuación.
El escenario siguiente hará que el enlazador genere errores de símbolo para las clases definidas por multiplicación. Supongamos que va a exportar una clase derivada de CString
(CMyString
) de un archivo DLL de extensión MFC:
// MyString.h
class AFX_EXT_CLASS CMyString : public CString
{
// Your implementation code
};
El código de consumidor usa una combinación de CString
y CMyString
. "MyString.h" no se incluye en el encabezado precompilado y algún uso de CString
no tiene CMyString
visible.
Supongamos que usa las clases CString
y CMyString
en archivos de código fuente independientes, Source1.cpp y Source2.cpp. En Source1.cpp, se usa CMyString
y #include MyString.h. En Source2.cpp, se usa CString
, pero no #include MyString.h. En este caso, el enlazador se quejará de que CStringT
esté definido por multiplicación. Esto se debe a que el compilador, mediante la plantilla CStringT
, importa CString
desde el archivo DLL que exporta CMyString
y crea instancias localmente.
Para resolver el problema, realice una de las acciones siguientes:
Exporte CStringA
y CStringW
(y las clases base necesarias) de MFC90.DLL. Los proyectos que incluyen MFC siempre usarán CStringA
y CStringW
exportados del archivo DLL de MFC, como en las implementaciones anteriores de MFC.
A continuación, cree una clase derivada exportable mediante la CStringT
plantilla, como CStringT_Exported
se muestra a continuación, por ejemplo:
#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
};
En AfxStr.h, reemplace las definiciones de tipo CString
, CStringA
y CStringW
anteriores de la siguiente manera:
typedef CStringT_Exported< wchar_t,
StrTraitMFC< wchar_t > > CStringW;
typedef CStringT_Exported< char,
StrTraitMFC< char > > CStringA;
typedef CStringT_Exported< TCHAR,
StrTraitMFC< TCHAR > > CString;
Hay algunas advertencias:
No debe exportarse
CStringT
, porque esto hará que los proyectos de ATL solo exportan una claseCStringT
especializada.El uso de una clase derivada exportable de
CStringT
minimiza la necesidad de volver a implementar la funcionalidadCStringT
. El código adicional se limita a reenviar constructores a la clase baseCStringT
.CString
,CStringA
yCStringW
solo se deben marcar cuando__declspec(dllexport/dllimport)
se compila con un archivo DLL de MFC compartido. Si se vincula con una biblioteca estática de MFC, no debe marcar estas clases como exportadas; de lo contrario, el uso interno deCString
,CStringA
yCStringW
dentro de los archivos DLL de usuario también marcaráCString
como exportado.