Simplemente hice algo como esto en C ++ por error y funciona. ¿Por qué puedo hacer esto?
int main(int argc, char** argv) {
struct MyStruct
{
int somevalue;
};
MyStruct s;
s.somevalue = 5;
}
Ahora, después de hacer esto, recordé haber leído sobre este truco en algún lugar, hace mucho tiempo, como una especie de herramienta de programación funcional de los pobres para C ++, pero no puedo recordar por qué esto es válido, o dónde lo leí.
¡Las respuestas a cualquiera de las preguntas son bienvenidas!
Nota: Aunque al escribir la pregunta no obtuve ninguna referencia a esta pregunta , la barra lateral actual lo señala, así que lo pondré aquí como referencia, de cualquier manera la pregunta es diferente pero podría ser útil.
c++
data-structures
functional-programming
Robert Gould
fuente
fuente
Respuestas:
[EDITAR 18/4/2013]: Felizmente, la restricción mencionada a continuación se ha eliminado en C ++ 11, ¡así que las clases definidas localmente son útiles después de todo! Gracias al comentarista bamboon.
La capacidad de definir clases localmente haría que la creación de functores personalizados (clases con
operator()()
, por ejemplo, funciones de comparación para pasarstd::sort()
o "cuerpos de bucle" para usarstd::for_each()
) sea mucho más conveniente.Desafortunadamente, C ++ prohíbe el uso de clases definidas localmente con plantillas , ya que no tienen vínculos. Dado que la mayoría de las aplicaciones de functores involucran tipos de plantilla que se basan en el tipo de functor, las clases definidas localmente no se pueden usar para esto; debe definirlas fuera de la función. :(
[EDITAR 11/1/2009]
La cotización relevante de la norma es:
fuente
Una aplicación de clases de C ++ definidas localmente está en el patrón de diseño de fábrica :
// In some header class Base { public: virtual ~Base() {} virtual void DoStuff() = 0; }; Base* CreateBase( const Param& ); // in some .cpp file Base* CreateBase( const Params& p ) { struct Impl: Base { virtual void DoStuff() { ... } }; ... return new Impl; }
Aunque puede hacer lo mismo con el espacio de nombres anónimo.
fuente
En realidad, es muy útil para realizar un trabajo de seguridad de excepciones basado en pilas. O limpieza general de una función con múltiples puntos de retorno. Esto a menudo se denomina el idioma RAII (adquisición de recursos es inicialización).
void function() { struct Cleaner { Cleaner() { // do some initialization code in here // maybe start some transaction, or acquire a mutex or something } ~Cleaner() { // do the associated cleanup // (commit your transaction, release your mutex, etc.) } }; Cleaner cleaner; // Now do something really dangerous // But you know that even in the case of an uncaught exception, // ~Cleaner will be called. // Or alternatively, write some ill-advised code with multiple return points here. // No matter where you return from the function ~Cleaner will be called. }
fuente
Cleaner cleaner();
Creo que esta será una declaración de función en lugar de una definición de objeto.Cleaner cleaner;
oCleaner cleaner{};
.Bueno, básicamente, ¿por qué no? A
struct
en C (que se remonta a los albores de los tiempos) era solo una forma de declarar una estructura de registro. Si quiere uno, ¿por qué no poder declararlo donde declararía una variable simple?Una vez que haga eso, recuerde que el objetivo de C ++ era ser compatible con C si fuera posible. Así que se quedó.
fuente
Se menciona, por ejemplo, en la sección "7.8: Clases locales: clases dentro de funciones" de http://www.icce.rug.nl/documents/cplusplus/cplusplus07.html que lo llama una "clase local" y lo dice " puede ser muy útil en aplicaciones avanzadas que involucren herencia o plantillas ".
fuente
Sirve para crear matrices de objetos que estén correctamente inicializados.
Tengo una clase C que no tiene un constructor predeterminado. Quiero una matriz de objetos de la clase C.Descubro cómo quiero que esos objetos se inicialicen, luego derivo una clase D de C con un método estático que proporciona el argumento para C en el constructor predeterminado de D:
#include <iostream> using namespace std; class C { public: C(int x) : mData(x) {} int method() { return mData; } // ... private: int mData; }; void f() { // Here I am in f. I need an array of 50 C objects starting with C(22) class D : public C { public: D() : C(D::clicker()) {} private: // I want my C objects to be initialized with consecutive // integers, starting at 22. static int clicker() { static int current = 22; return current++; } }; D array[50] ; // Now I will display the object in position 11 to verify it got initialized // with the right value. cout << "This should be 33: --> " << array[11].method() << endl; cout << "sizodf(C): " << sizeof(C) << endl; cout << "sizeof(D): " << sizeof(D) << endl; return; } int main(int, char **) { f(); return 0; }
En aras de la simplicidad, este ejemplo utiliza un constructor trivial no predeterminado y un caso en el que los valores se conocen en el momento de la compilación. Es sencillo extender esta técnica a los casos en los que desee que se inicialice una matriz de objetos con valores que solo se conocen en tiempo de ejecución.
fuente
D*
parámetro), esto se romperá silenciosamente si D es en realidad más grande que C . (Creo ...)