Trabajar con código de C++ en el Diseñador de clases

El Diseñador de clases muestra una superficie de diseño visual denominada diagrama de clases que ofrece una representación visual de los elementos de código del proyecto. Puede usar diagramas de clases para diseñar y visualizar clases y otros tipos en un proyecto.

El Diseñador de clases admite los siguientes elementos de código de C++:

  • Clase (se asemeja a una forma de clase administrada, salvo que puede tener varias relaciones de herencia)

  • Clase anónima (muestra el nombre de la vista de clase que se genera para el tipo anónimo)

  • Clase de plantilla

  • Struct

  • Enum

  • Macro (muestra la vista posterior al proceso de la macro)

  • Definición de tipo

Nota

No es igual que el diagrama de clases UML, que se puede crear en un proyecto de modelado. Para obtener más información, vea Diagramas de clases de UML: referencia.

Clases de C++ en el Diseñador de clases

El Diseñador de clases admite las clases de C++ y visualiza las clases nativas de C++ igual que las formas de clase de Visual Basic y C#, con la diferencia de que las clases de C++ pueden tener varias relaciones de herencia. Puede expandir la forma de clase para que muestre más campos y métodos de la clase o contraerla para ahorrar espacio.

Nota

El Diseñador de clases no admite las uniones (un tipo especial de clase en la que la memoria asignada solo es la cantidad necesaria para el miembro de datos más grande de la unión).

Herencia simple

Cuando se arrastra más de una clase a un diagrama de clases y las clases tienen una relación de herencia de clase, se conectan mediante una flecha. La flecha apunta en la dirección de la clase base. Por ejemplo, cuando las clases siguientes se muestran en un diagrama de clases, se conectan mediante una flecha que apunta de B a A:

class A {};
class B : A {};

También puede arrastrar únicamente la clase B al diagrama de clases, hacer clic con el botón derecho en la forma de clase de B y hacer clic en Mostrar clases base. De este modo se muestra su clase base: A.

Herencia múltiple

El Diseñador de clases admite la visualización de relaciones de herencia de varias clases. La herencia múltiple se usa cuando una clase derivada tiene atributos de más de una clase base. A continuación se muestra un ejemplo de herencia múltiple:

class Bird {};
class Swimmer {};
class Penguin : public Bird, public Swimmer {};

Cuando se arrastra más de una clase al diagrama de clases y las clases tienen una relación de herencia de varias clases, se conectan mediante una flecha. La flecha apunta en la dirección de las clases base.

Si hace clic con el botón derecho en una forma de clase y, después, hace clic en Mostrar clases base, se muestran las clases base de la clase seleccionada.

Nota

No se admite el comando Mostrar clases derivadas para el código de C++. Para mostrar las clases derivadas, vaya a la Vista de clases, expanda el nodo de tipo, expanda la subcarpeta Tipos derivados y arrastre esos tipos al diagrama de clases.

Para obtener más información sobre la herencia de varias clases, vea Herencia múltiple y Multiple Base Classes (Varias clases base).

Clases abstractas

El Diseñador de clases admite clases abstractas (también denominadas "clases base abstractas"). Se trata de clases de las que nunca se crean instancias, pero de las que se pueden derivar otras clases. Mediante un ejemplo de la anterior sección "Herencia múltiple" de este documento, puede crear instancias de la clase Bird como objetos individuales de la manera siguiente:

int main()
{
   Bird sparrow;
   Bird crow;
   Bird eagle;
}

Pero tal vez no piense crear instancias de la clase Swimmer como objetos individuales, sino simplemente derivar otros tipos de clases de animales, como Penguin, Whale y Fish. En ese caso, declararía la clase Swimmer como una clase base abstracta.

Para declarar una clase como abstracta, puede usar la palabra clave abstract. Los miembros marcados como abstractos o incluidos en una clase abstracta son virtuales y deben implementarse con clases que deriven de la clase abstracta.

class Swimmer abstract
{
   virtual void swim();
   void dive();
};

También puede declarar una clase como abstracta si incluye al menos una función virtual pura:

class Swimmer
{
   virtual void swim() = 0;
   void dive();
};

Al mostrar estas declaraciones en un diagrama de clases, el nombre de clase Swimmer y su función virtual pura swim aparecen en cursiva en una forma de clase abstracta, junto con la notación Clase abstracta. Observe que la forma del tipo de clase abstracta es igual que la de una clase normal, con la diferencia de que su borde es una línea de puntos.

Una clase derivada de una clase base abstracta debe invalidar todas las funciones virtuales puras de la clase base. De lo contrario, no se podrán crear instancias de la clase derivada. Así pues, por ejemplo, si deriva una clase Fish de la clase Swimmer, Fish debe invalidar el método swim:

class Fish : public Swimmer
{
   void swim(int speed);
};

int main()
{
   Fish guppy;
}

Cuando este código se muestra en un diagrama de clases, el Diseñador de clases dibuja una línea de herencia de Fish a Swimmer.

Clases anónimas

El Diseñador de clases admite las clases anónimas. Los tipos de clase anónima son clases declaradas sin un identificador. No pueden tener un constructor o un destructor, no se pueden pasar como argumentos a funciones y no se pueden devolver como valores devueltos de funciones. Puede usar una clase anónima para reemplazar un nombre de clase con un nombre de typedef, como en el ejemplo siguiente:

typedef struct
{
    unsigned x;
    unsigned y;
} POINT;

Las estructuras también pueden ser anónimas. El Diseñador de clases muestra las clases y las estructuras anónimas del mismo modo que muestra el tipo respectivo. Aunque puede declarar y mostrar clases y estructuras anónimas, el Diseñador de clases no usa el nombre de etiqueta especificado, sino que usará el nombre que genere la Vista de clases. La clase o estructura aparece en la Vista de clases y el Diseñador de clases como un elemento denominado __unnamed.

Para más información sobre las clases anónimas, vea Tipos de clase anónima.

Clases de plantillas

El Diseñador de clases admite la visualización de clases de plantillas. Se admiten las declaraciones anidadas. En la tabla siguiente se muestran algunas declaraciones típicas.

Elemento de código Vista Diseñador de clases
template <class T>

class A {};
A<T>

Clase de plantilla
template <class T, class U>

class A {};
A<T, U>

Clase de plantilla
template <class T, int i>

class A {};
A<T, i>

Clase de plantilla
template <class T, template <class K> class U>

class A {};
A<T, U>

Clase de plantilla

En la tabla siguiente se muestran algunos ejemplos de especialización parcial.

Elemento de código Vista Diseñador de clases
template<class T, class U>

class A {};
A<T, U>

Clase de plantilla
template<class T>

class A<T, T> {};
A<T, T>

Clase de plantilla
template <class T>

class A<T, int> {};
A<T, int>

Clase de plantilla
template <class T1, class T2>

class A<T1*, T2*> {};
A<T1*, T2*>

Clase de plantilla

En la tabla siguiente se muestran algunos ejemplos de herencia en especialización parcial.

Elemento de código Vista Diseñador de clases
template <class T, class U>

class A {};

template <class TC>

class A<T, int> {};

class B : A<int, float>

{};

class C : A<int, int>

{};
A<T, U>

Clase de plantilla

B

Clase

(apunta a la clase A)

C

Clase

(apunta a la clase A)

En la tabla siguiente se muestran algunos ejemplos de funciones de plantilla de especialización parcial.

Elemento de código Vista Diseñador de clases
class A

{

template <class T, class U>

void func(T a, U b);

template <class T>

void func(T a, int b);

};
A

func<T, U> (+ 1 sobrecarga)
template <class T1>

class A {

template <class T2>

class B {};

};

template<> template<>

class A<type>::B<type> {};
A<T1>

Clase de plantilla

B<T2>

Clase de plantilla

(B se encuentra dentro de la clase A bajo Tipos anidados)
template <class T>

class C {};

class A : C<int> {};
A

Clase

-> C<int>

C<T>

Clase de plantilla

En la tabla siguiente se muestran algunos ejemplos de herencia de plantilla.

Elemento de código Vista Diseñador de clases
template <class T>

class C {};

template<>

class C<int> {

class B {};

}

class A : C<int>::B {};
A

Clase

->B

C<int>

Clase

(B se encuentra dentro de la clase C bajo Tipos anidados)

C<T>

Clase de plantilla

En la tabla siguiente se muestran algunos ejemplos de conexión de clases especializadas canónicas.

Elemento de código Vista Diseñador de clases
template <class T>

class C {};

template<>

class C<int> {};

class A : C<int> {};

class D : C<float> {};
A

Clase

->C<int>

C<int>

Clase

C<T>

Clase de plantilla

D

Clase

->C<float>
class B {

template <class T>

T min (const T &a, const T &b);

};
B

min <T>

Enumeraciones de C++ en el Diseñador de clases

El Diseñador de clases admite tipos enum y enum class de ámbito de C++. El siguiente es un ejemplo:

enum CardSuit {
   Diamonds = 1,
   Hearts = 2,
   Clubs = 3,
   Spades = 4
};

// or...
enum class CardSuit {
   Diamonds = 1,
   Hearts = 2,
   Clubs = 3,
   Spades = 4
};

Una forma de enumeración de C++ en un diagrama de clases se parece y funciona como una forma de estructura, salvo que en la etiqueta se muestra Enum o Enum class, es de color fucsia en lugar de azul y el borde de los márgenes superior e izquierdo está coloreado. Tanto las formas de enumeración como las formas de estructura tienen las esquinas cuadradas.

Para obtener más información sobre cómo usar el tipo enum, vea Enumerations (Enumeraciones).

Definiciones de tipo de C++ en el Diseñador de clases

Las instrucciones TypeDef crean una o varias capas de direccionamiento indirecto entre un nombre y su tipo subyacente. El Diseñador de clases admite los tipos de definición de tipo de C++, que se declaran con la palabra clave typedef; por ejemplo:

typedef class coord
{
   void P(x,y);
   unsigned x;
   unsigned y;
} COORD;

A continuación, puede usar este tipo para declarar una instancia:

COORD OriginPoint;

Formas de clase y estructura

En el Diseñador de clases, una definición de tipo de C++ tiene la forma del tipo especificado en la definición de tipo. Si el origen declara typedef class, la forma tiene esquinas redondeadas y la etiqueta Class. Para typedef struct, la forma tiene esquinas cuadradas y la etiqueta Struct.

Las clases y estructuras pueden tener definiciones de tipo anidadas que estén declaradas dentro de ellas. En el Diseñador de clases, las formas de clase y estructura pueden mostrar declaraciones de definición de tipo anidadas como formas anidadas.

Las formas de TypeDef admiten los comandos Mostrar como asociación y Mostrar como asociación de colecciones en el menú contextual.

Ejemplo de definición de tipo de clase

class B {};
typedef B MyB;

C++ class typedef in Class Designer

Ejemplo de definición de tipo de estructura

typedef struct mystructtag
{
    int   i;
    double f;
} mystruct;

C++ struct typedef in Class Designer

Definiciones de tipo sin nombre

Aunque se puede declarar una definición de tipo sin nombre, el Diseñador de clases no usará el nombre de etiqueta que se especifique. El Diseñador de clases usa el nombre que genera Vista de clases. Por ejemplo, la siguiente declaración es válida, pero aparece en la Vista de clases y en el Diseñador de clases como un objeto denominado __unnamed:

typedef class coord
{
   void P(x,y);
   unsigned x;
   unsigned y;
};

Nota:

El Diseñador de clases no muestra ninguna definición de tipo cuyo tipo de origen es un puntero de función.

Más información sobre las limitaciones de los elementos de código de C++

  • Cuando se carga un proyecto de C++, el Diseñador de clases funciona en modo de solo lectura. Puede cambiar el diagrama de clases, pero no guardar cambios desde el diagrama de clases en el código fuente.

  • El Diseñador de clases solo admite semántica de C++ nativa. En proyectos de C++ que se compilan en código administrado, el Diseñador de clases solo presenta elementos de código que son tipos nativos. Por lo tanto, puede agregar un diagrama de clases a un proyecto, pero el Diseñador de clases no le permite ver los elementos en los que la propiedad IsManaged se establece en true (es decir, tipos de valor y tipos de referencia).

  • En proyectos de C++, el Diseñador de clases solo lee la definición del tipo. Por ejemplo, suponga que define un tipo en un archivo de encabezado (.h) y define sus miembros en un archivo de implementación (.cpp). Si llama a "Ver diagrama de clases" en el archivo de implementación (.cpp), el Diseñador de clases no muestra nada. Otro ejemplo, si llama a "Ver diagrama de clases" en un archivo .cpp que usa una instrucción #include para incluir otros archivos pero no contiene ninguna definición de clase real, el Diseñador de clases tampoco muestra nada.

  • Los archivos IDL (.idl), que definen las interfaces COM y las bibliotecas de tipos, no se muestran en los diagramas a menos que se compilen en código C++ nativo.

  • El Diseñador de clases no admite funciones ni variables globales.

  • El Diseñador de clases no admite uniones. Se trata de un tipo especial de clase en la que la memoria asignada solo es la cantidad necesaria para el miembro de datos más grande de la unión.

  • El Diseñador de clases no muestra tipos de datos básicos como int y char.

  • El Diseñador de clases no muestra tipos definidos fuera del proyecto actual si el proyecto no tiene referencias correctas a esos tipos.

  • El Diseñador de clases puede mostrar tipos anidados, pero no las relaciones entre un tipo anidado y otros tipos.

  • El Diseñador de clases no puede mostrar tipos que sean de tipo void o que deriven de un tipo void.

Solucionar problemas de visualización y resolución de tipos

Ubicación de archivos de origen

El Diseñador de clases no realiza un seguimiento de la ubicación de los archivos de origen. Por lo tanto, si modifica la estructura del proyecto o mueve archivos de origen del proyecto, el Diseñador de clases puede perder la pista del tipo (sobre todo del tipo de origen de una definición de tipo, clases base o tipos de asociación). Puede que obtenga un error, como El Diseñador de clases no puede mostrar este tipo. Si lo recibe, arrastre otra vez el código fuente modificado o reubicado al diagrama de clases para volver a mostrarlo.

Problemas de actualización y rendimiento

En los proyectos de C++, puede tardarse entre 30 y 60 segundos para que un cambio en el archivo de código fuente aparezca en el diagrama de clases. Es posible que este retraso también provoque que el Diseñador de clases produzca el error No se encontraron tipos en la selección. Si recibe un error de este tipo, haga clic en Cancelar en el mensaje de error y espere a que el elemento de código aparezca en la Vista de clases. Después de esto, el Diseñador de clases debe poder mostrar el tipo.

Si un diagrama de clases no se actualiza con los cambios realizados en el código, es posible que tenga que cerrar el diagrama y volver a abrirlo.

Problemas de resolución de tipos

Puede que el Diseñador de clases no pueda resolver tipos por las razones siguientes:

  • El tipo está en un proyecto o ensamblado al que no se hace referencia desde el proyecto que contiene el diagrama de clases. Para corregir este error, agregue una referencia al proyecto o ensamblado que contiene el tipo. Para más información, vea Administrar referencias en un proyecto.

  • El tipo no está en el ámbito correcto, por lo que el Diseñador de clases no puede encontrarlo. Asegúrese de que al código no le falta una instrucción using, imports o #include. Asegúrese también de que no quitó el tipo (o un tipo relacionado) del espacio de nombres en el que se encontraba originalmente.

  • El tipo no existe (o se convirtió en comentario). Para corregir este error, asegúrese de que no convirtió el tipo en comentario ni lo eliminó.

  • El tipo se encuentra en una biblioteca a la que hace referencia una directiva #import. Una posible solución alternativa es agregar manualmente el código generado (archivo .tlh) a una directiva #include en el archivo de encabezado.

  • Asegúrese de que el Diseñador de clases admite el tipo especificado. Vea Limitaciones de los elementos de código C++.

El error que probablemente más va a encontrar para un problema de resolución de tipos es No se pudo encontrar el código para una o varias formas en el diagrama de clase "<element>". Este mensaje de error no necesariamente indica que el código sea incorrecto. Solo indica que ese diseñador de clases no pudo mostrar el código. Pruebe las siguientes medidas:

  • Asegúrese de que el tipo existe. Asegúrese de que no eliminó involuntariamente el código fuente ni lo convirtió en comentario.

  • Intente resolver el tipo. Puede que el tipo esté en un proyecto o ensamblado al que no se hace referencia desde el proyecto que contiene el diagrama de clases. Para corregir este error, agregue una referencia al proyecto o ensamblado que contiene el tipo. Para más información, vea Administrar referencias en un proyecto.

  • Asegúrese de que el tipo está en el ámbito correcto para que el Diseñador de clases pueda encontrarlo. Asegúrese de que al código no le falta una instrucción using, imports o #include. Asegúrese también de que no quitó el tipo (o un tipo relacionado) del espacio de nombres en el que se encontraba originalmente.

Sugerencia

Para obtener más información de solución de problemas, consulte Errores de Diseñador de clases.