¿En qué escenarios es mejor usar un struct
vs a class
en C ++?
¿En qué escenarios es mejor usar un struct
vs a class
en C ++?
Respuestas:
Las diferencias entre a class
y a struct
en C ++ son que las estructuras tienen public
miembros y bases predeterminados y las clases tienen private
miembros y bases predeterminados . Ambas clases y las estructuras pueden tener una mezcla de public
, protected
yprivate
los miembros, pueden utilizar la herencia y pueden tener funciones miembro.
Recomendaría usar estructuras como estructuras de datos antiguos sin ninguna clase de características, y usar clases como estructuras de datos agregados con private
datos y funciones miembro.
Como todos los demás señalan, en realidad solo hay dos diferencias de idioma reales:
struct
valores predeterminados de acceso público y class
valores predeterminados de acceso privado.struct
predeterminado es public
herencia y el valor class
predeterminado es private
herencia. (Irónicamente, como con tantas cosas en C ++, el valor predeterminado es al revés: la public
herencia es, con mucho, la opción más común, pero la gente rara vez declara struct
s solo para ahorrar al escribir la public
palabra clave " ".Pero la verdadera diferencia en la práctica es entre un class
/ struct
que declara un constructor / destructor y uno que no. Hay ciertas garantías para un tipo de POD de "datos antiguos", que ya no se aplican una vez que se hace cargo de la construcción de la clase. Para mantener esta distinción clara, muchas personas deliberadamente solo usan struct
s para los tipos de POD y, si van a agregar algún método, usan class
es. La diferencia entre los dos fragmentos a continuación no tiene sentido:
class X
{
public:
// ...
};
struct X
{
// ...
};
(Por cierto, aquí hay un hilo con algunas buenas explicaciones sobre lo que realmente significa "tipo POD": ¿Qué son los tipos POD en C ++? )
struct
o class
no tiene relación con si su objeto es POD o si debe definir un constructor / destructor de copia. Las funciones de los miembros tampoco tienen relación con que algo sea POD. Cuando vuelvo a leer lo que escribiste, veo que no estás sugiriendo lo contrario, pero la redacción actual es confusa
Hay muchas ideas falsas en las respuestas existentes.
Ambos class
y struct
declarar una clase.
Sí, es posible que deba reorganizar sus palabras clave de modificación de acceso dentro de la definición de clase, según la palabra clave que utilizó para declarar la clase.
Pero, más allá de la sintaxis, la única razón para elegir una sobre la otra es la convención / estilo / preferencia.
A algunas personas les gusta seguir con la struct
palabra clave para clases sin funciones de miembro, porque la definición resultante "parece" una estructura simple de C.
Del mismo modo, a algunas personas les gusta usar la class
palabra clave para las clases con funciones y private
datos de miembros , porque dice "clase" y, por lo tanto, parece ejemplos de su libro favorito sobre programación orientada a objetos.
La realidad es que esto depende completamente de usted y su equipo, y literalmente no hará ninguna diferencia en su programa.
Las siguientes dos clases son absolutamente equivalentes en todos los sentidos, excepto su nombre:
struct Foo
{
int x;
};
class Bar
{
public:
int x;
};
Incluso puede cambiar las palabras clave al volver a declarar:
class Foo;
struct Bar;
(aunque esto rompe las compilaciones de Visual Studio debido a la no conformidad, por lo que el compilador emitirá una advertencia cuando haga esto).
y las siguientes expresiones se evalúan como verdaderas:
std::is_class<Foo>::value
std::is_class<Bar>::value
Sin embargo, tenga en cuenta que no puede cambiar las palabras clave al redefinir ; esto es solo porque (según la regla de una definición) las definiciones de clase duplicadas en las unidades de traducción deben "consistir en la misma secuencia de tokens" . Esto significa que incluso no pueden intercambiar const int member;
con int const member;
, y no tiene nada que ver con la semántica de class
o struct
.
class foo { public: ... };
y otra pueda tener struct foo { ... };
que ser cierta según la afirmación "absolutamente equivalente". Se trata de razonar que las declaraciones incompletas struct foo;
y class foo;
son intercambiables. Estos no especifican el cuerpo de la clase, por lo que no le dicen nada al diseño de acceso.
Foo
y Bar
son todavía equivalente / tipos idénticos. Me aseguré de decir "al redeclar " y dar un ejemplo. Ahora que lo pienso, aclararé esto en la respuesta para asegurarme de que no estoy engañando a la gente a UB
La única vez que uso una estructura en lugar de una clase es cuando declaro un functor justo antes de usarlo en una llamada de función y quiero minimizar la sintaxis en aras de la claridad. p.ej:
struct Compare { bool operator() { ... } };
std::sort(collection.begin(), collection.end(), Compare());
Desde C ++ FAQ Lite :
Los miembros y las clases base de una estructura son públicos por defecto, mientras que en la clase, por defecto son privados. Nota: debe hacer que sus clases base sean explícitamente públicas, privadas o protegidas, en lugar de depender de los valores predeterminados.
struct y class son funcionalmente equivalentes.
OK, suficiente de esa charla techno chirriante y limpia. Emocionalmente, la mayoría de los desarrolladores hacen una fuerte distinción entre una clase y una estructura. Una estructura simplemente se siente como una pila abierta de bits con muy poca encapsulación o funcionalidad. Una clase se siente como un miembro vivo y responsable de la sociedad con servicios inteligentes, una fuerte barrera de encapsulación y una interfaz bien definida. Dado que esa es la connotación que la mayoría de la gente ya tiene, probablemente debería usar la palabra clave struct si tiene una clase que tiene muy pocos métodos y tiene datos públicos (¡tales cosas existen en sistemas bien diseñados!), Pero de lo contrario, probablemente debería usar la clase palabra clave.
Un lugar donde una estructura me ha sido útil es cuando tengo un sistema que recibe mensajes de formato fijo (por ejemplo, un puerto serie) de otro sistema. Puede convertir la secuencia de bytes en una estructura que define sus campos y luego acceder fácilmente a los campos.
typedef struct
{
int messageId;
int messageCounter;
int messageData;
} tMessageType;
void processMessage(unsigned char *rawMessage)
{
tMessageType *messageFields = (tMessageType *)rawMessage;
printf("MessageId is %d\n", messageFields->messageId);
}
Obviamente, esto es lo mismo que haría en C, pero creo que la sobrecarga de tener que decodificar el mensaje en una clase generalmente no vale la pena.
operator >>
en una clase en lugar de escribir la processMessage
función, lo que haría que su C ++ se parezca más a C ++ y menos a C.
__packed__
estructura y tener una implementación ifdef compatible con endian (debe cambiar el orden en una máquina donde la endianess es opuesta a la fuente de datos externa está proporcionando). No es bonito, pero solía empacar / desempaquetar registros para periféricos remotos en plataformas integradas de forma portátil.
char
tipo, que está exento de alias. Sin embargo, todavía hay un problema, aunque diferente: enviar un char*
a un tipo diferente, si realmente no había ningún objeto del último tipo ya inicializado en esa dirección, es UB ya que viola las reglas de por vida. Afaik, incluso si el tipo de destino es trivialmente construible, simplemente tener memoria asignada no es suficiente para que C ++ permita formalmente tratar esa memoria como ese tipo.
Puede usar "struct" en C ++ si está escribiendo una biblioteca cuyas partes internas son C ++ pero la API puede ser llamada por código C o C ++. Simplemente haga un encabezado único que contenga estructuras y funciones API globales que exponga a los códigos C y C ++ de la siguiente manera:
// C access Header to a C++ library
#ifdef __cpp
extern "C" {
#endif
// Put your C struct's here
struct foo
{
...
};
// NOTE: the typedef is used because C does not automatically generate
// a typedef with the same name as a struct like C++.
typedef struct foo foo;
// Put your C API functions here
void bar(foo *fun);
#ifdef __cpp
}
#endif
Luego puede escribir una barra de función () en un archivo C ++ usando el código C ++ y hacer que se pueda llamar desde C y los dos mundos pueden compartir datos a través de la estructura declarada. Existen otras advertencias, por supuesto, cuando se mezclan C y C ++, pero este es un ejemplo simplificado.
Como todos dicen, la única diferencia real es el acceso predeterminado. Pero particularmente uso struct cuando no quiero ningún tipo de encapsulación con una clase de datos simple, incluso si implemento algunos métodos auxiliares. Por ejemplo, cuando necesito algo como esto:
struct myvec {
int x;
int y;
int z;
int length() {return x+y+z;}
};
Para responder a mi propia pregunta (descaradamente), como ya se mencionó, los privilegios de acceso son la única diferencia entre ellos en C ++.
Tiendo a usar una estructura solo para almacenamiento de datos. Le permitiré obtener algunas funciones auxiliares si facilita el trabajo con los datos. Sin embargo, tan pronto como los datos requieran control de flujo (es decir, captadores / establecedores que mantengan o protejan un estado interno) o comience a adquirir cualquier funcionalidad importante (básicamente más similar a un objeto), se 'actualizará' a una clase para comunicar mejor la intención.
Las estructuras ( POD , en general) son útiles cuando se proporciona una interfaz compatible con C con una implementación de C ++, ya que son portátiles a través de las fronteras del lenguaje y los formatos de enlace.
Si eso no le preocupa, entonces supongo que el uso de la "estructura" en lugar de la "clase" es un buen comunicador de intenciones (como dijo anteriormente @ZeroSignal). Las estructuras también tienen una semántica de copia más predecible, por lo que son útiles para los datos que tiene la intención de escribir en medios externos o enviar a través del cable.
Las estructuras también son útiles para diversas tareas de metaprogramación, como las plantillas de rasgos que solo exponen un montón de definiciones de tipos dependientes:
template <typename T> struct type_traits {
typedef T type;
typedef T::iterator_type iterator_type;
...
};
... Pero eso es solo aprovechar el nivel de protección predeterminado de struct que es público ...
Para C ++, realmente no hay mucha diferencia entre estructuras y clases. La principal diferencia funcional es que los miembros de una estructura son públicos de forma predeterminada, mientras que son privados de forma predeterminada en las clases. De lo contrario, en lo que respecta al idioma, son equivalentes.
Dicho esto, tiendo a usar estructuras en C ++ como lo hago en C #, similar a lo que Brian ha dicho. Las estructuras son contenedores de datos simples, mientras que las clases se usan para objetos que necesitan actuar sobre los datos además de simplemente retenerlos.
Son más o menos lo mismo. Gracias a la magia de C ++, una estructura puede contener funciones, usar herencia, crearse usando "nuevo", etc., como una clase
La única diferencia funcional es que una clase comienza con derechos de acceso privado, mientras que una estructura comienza con público. Esta es la compatibilidad con versiones anteriores de C.
En la práctica, siempre he usado estructuras como titulares de datos y clases como objetos.
Como otros han señalado
Hay una recomendación clara sobre cuándo usar cuál de Stroustrup / Sutter:
Sin embargo, tenga en cuenta que no es aconsejable reenviar declaraciones. como una clase ( class X;
) y definirlo como struct ( struct X { ... }
). Puede funcionar en algunos enlazadores (por ejemplo, g ++) y puede fallar en otros (por ejemplo, MSVC), por lo que se encontrará en el infierno del desarrollador.
class Foo; struct Foo { void bar() {} }; int main() { Foo().bar(); }
no solo compila y se ejecuta con MSVC 2017, incluso produce una advertencia clara que Foo
fue declarada como struct
pero definida como class
. Pero también recuerdo claramente que le costó a nuestro equipo medio día encontrar ese estúpido error. No estoy seguro de qué versión de MSVC hemos usado en ese entonces.
class
o struct
en una declaración de reenvío, y los dos son libremente intercambiables según el estándar (aunque se sabe que VS advierte; siempre supuse que era solo para evitar errores aparentes del programador). Algo no huele bien aquí. ¿Estás seguro de que no fue un error de violación de ODR?
struct
avance hacia class
adelante, los problemas desaparecieron. A partir de hoy, también me parece extraño. Me alegraría si pudieras arrojar algo de luz sobre ello.
Los miembros de la clase son privados por defecto.
class test_one {
int main_one();
};
Es equivalente a
class test_one {
private:
int main_one();
};
Entonces si lo intentas
int two = one.main_one();
Obtendremos un error: main_one is private
porque no es accesible. Podemos resolverlo inicializándolo especificando que es un público, es decir
class test_one {
public:
int main_one();
};
Una estructura es una clase donde los miembros son públicos de forma predeterminada.
struct test_one {
int main_one;
};
Medios main_one
es privado es decir
class test_one {
public:
int main_one;
};
Utilizo estructuras para estructuras de datos donde los miembros pueden tomar cualquier valor, así es más fácil.
Una ventaja de struct
over class
es que guarda una línea de código, si se adhiere a "primero miembros públicos, luego privados". En este sentido, encuentro la palabra claveclass
inútil.
Aquí hay otra razón para usar solo struct
y nunca class
. Algunas pautas de estilo de código para C ++ sugieren el uso de letras minúsculas para las macros de funciones, la razón es que cuando la macro se convierte en una función en línea, no es necesario cambiar el nombre. Igual que aquí. Tiene su estructura de estilo C agradable y un día, descubre que necesita agregar un constructor, o algún método conveniente. ¿Lo cambias a a class
? ¿En todas partes?
Distinguir entre struct
sy class
es es demasiado complicado, interponerse en la forma de hacer lo que deberíamos estar haciendo: programar. Como muchos de los problemas de C ++, surge del fuerte deseo de compatibilidad hacia atrás.
class
? ¿Pensó que una clase definida con la struct
palabra clave no puede tener funciones miembro o un constructor?
joe()
debe definirse con una class
palabra clave? ¿Cada clase con al menos 4 int
miembros debe definirse con una struct
palabra clave?
struct
, los agregados con métodos se definen con class
". Demasiada molestia.
son lo mismo con diferentes valores predeterminados (privado por defecto para class
y público por defecto para struct
), por lo que en teoría son totalmente intercambiables.
entonces, si solo quiero empaquetar información para moverme, uso una estructura, incluso si pongo algunos métodos allí (pero no muchos). Si es algo opaco en su mayoría, donde el uso principal sería a través de métodos, y no directamente a los miembros de datos, utilizo una clase completa.
Las estructuras por defecto tienen acceso público y las clases por defecto tienen acceso privado.
Personalmente, uso estructuras para objetos de transferencia de datos o como objetos de valor. Cuando se usa como tal, declaro que todos los miembros son constantes para evitar modificaciones por otro código.
Tanto struct
y class
son los mismos bajo el capó, aunque con diferentes valores por defecto en cuanto a visibilidad, struct
por defecto es público y class
por defecto es privado. Puede cambiar uno para que sea el otro con el uso apropiado de private
ypublic
. Ambos permiten la herencia, los métodos, los constructores, los destructores y todo lo demás de un lenguaje orientado a objetos.
Sin embargo, una gran diferencia entre los dos es que struct
una palabra clave se admite en C, mientras class
que no. Esto significa que uno puede usar un struct
archivo de inclusión que puede estar #include
en C ++ o C siempre que struct
sea un estilo C simple struct
y todo lo demás en el archivo de inclusión sea compatible con C, es decir, sin palabras clave específicas de C ++ como private
, por ejemplo ,public
, sin métodos, sin herencia, etc. etc. etc.
El estilo AC struct
se puede usar con otras interfaces que admiten el uso del estilo C struct
para transportar datos de un lado a otro a través de la interfaz.
El estilo de CA struct
es un tipo de plantilla (no una plantilla de C ++ sino un patrón o plantilla) que describe el diseño de un área de memoria. Con los años las interfaces utilizable a partir de C y C con los plug-ins (aquí le está mirando Java y Python y Visual Basic) se han creado algunas de las cuales trabaja con el estilo C struct
.
Técnicamente, ambos son iguales en C ++; por ejemplo, es posible que una estructura tenga operadores sobrecargados, etc.
Sin embargo :
Utilizo estructuras cuando deseo pasar información de múltiples tipos simultáneamente. Uso clases cuando estoy tratando con un objeto "funcional".
Espero eso ayude.
#include <string>
#include <map>
using namespace std;
struct student
{
int age;
string name;
map<string, int> grades
};
class ClassRoom
{
typedef map<string, student> student_map;
public :
student getStudentByName(string name) const
{ student_map::const_iterator m_it = students.find(name); return m_it->second; }
private :
student_map students;
};
Por ejemplo, estoy devolviendo un estudiante de estructura en los métodos get ... () por aquí, disfruta.
¿Cuándo elegirías usar struct y cuándo usar class en C ++?
Yo uso struct
cuando defino functors
y POD
. De lo contrario lo uso class
.
// '()' is public by default!
struct mycompare : public std::binary_function<int, int, bool>
{
bool operator()(int first, int second)
{ return first < second; }
};
class mycompare : public std::binary_function<int, int, bool>
{
public:
bool operator()(int first, int second)
{ return first < second; }
};
std::binary_function<>
no solo está en desuso, incluso c ++ 17 la elimina.
Todos los miembros de la clase son privados de forma predeterminada y todos los miembros de la estructura son públicos de forma predeterminada. La clase tiene bases privadas predeterminadas y Struct tiene bases públicas predeterminadas. Struct en el caso de C no puede tener funciones miembro donde, como en el caso de C ++, podemos agregar funciones miembro a la estructura. Aparte de estas diferencias, no encuentro nada sorprendente sobre ellas.
Utilizo struct solo cuando necesito mantener algunos datos sin ninguna función miembro asociada (para operar con los datos miembros) y acceder a las variables de datos directamente.
Por ejemplo: lectura / escritura de datos de archivos y secuencias de socket, etc. Pasar argumentos de función en una estructura donde los argumentos de función son demasiados y la sintaxis de función parece demasiado larga.
Técnicamente no hay una gran diferencia entre clase y estructura, excepto la accesibilidad predeterminada. Más sobre eso depende del estilo de programación como lo use.
Pensé que Structs tenía la intención de ser una Estructura de datos (como una matriz de información de tipos de datos múltiples) y que las clases estaban destinadas al Empaquetado de código (como colecciones de subrutinas y funciones).
:(
Nunca uso "struct" en C ++.
No puedo imaginar un escenario en el que usarías una estructura cuando quieres miembros privados, a menos que intencionalmente intentes ser confuso.
Parece que el uso de estructuras es más una indicación sintáctica de cómo se usarán los datos, pero prefiero simplemente hacer una clase e intentar hacerlo explícito en el nombre de la clase, o mediante comentarios.
P.ej
class PublicInputData {
//data members
};
struct
sería ya bastante explícito que los miembros de la clase serán, por defecto, públicos?