J'ai juste fait par erreur quelque chose comme ça en C ++, et ça marche. Pourquoi puis-je faire ça?
int main(int argc, char** argv) {
struct MyStruct
{
int somevalue;
};
MyStruct s;
s.somevalue = 5;
}
Maintenant, après avoir fait cela, je me suis souvenu avoir lu quelque part à propos de cette astuce, il y a longtemps, comme une sorte d'outil de programmation fonctionnel pour homme pauvre pour C ++, mais je ne me souviens pas pourquoi cela est valide, ni où je l'ai lu.
Les réponses à l'une ou l'autre des questions sont les bienvenues!
Remarque: Bien que lors de la rédaction de la question, je n'ai pas obtenu de références à cette question , la barre latérale actuelle le souligne donc je la mets ici pour référence, de toute façon la question est différente mais pourrait être utile.
c++
data-structures
functional-programming
Robert Gould
la source
la source
Réponses:
[EDIT 18/4/2013]: Heureusement, la restriction mentionnée ci-dessous a été levée en C ++ 11, donc les classes définies localement sont utiles après tout! Merci au commentateur Bamboon.
La capacité de définir des classes au niveau local serait rendre la création foncteurs personnalisés (classes avec un
operator()()
, par exemple des fonctions de comparaison pour passer àstd::sort()
ou « corps de boucle » à utiliser avecstd::for_each()
) beaucoup plus pratique.Malheureusement, C ++ interdit l'utilisation de classes définies localement avec des modèles , car elles n'ont pas de lien. Étant donné que la plupart des applications de foncteurs impliquent des types de modèles qui sont basés sur le type de foncteur, les classes définies localement ne peuvent pas être utilisées pour cela - vous devez les définir en dehors de la fonction. :(
[EDIT 1/11/2009]
La citation pertinente de la norme est:
la source
Une application des classes C ++ définies localement est dans le modèle de conception Factory :
// 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; }
Bien que vous puissiez faire la même chose avec un espace de noms anonyme.
la source
C'est en fait très utile pour effectuer des travaux de sécurité des exceptions basés sur la pile. Ou nettoyage général d'une fonction avec plusieurs points de retour. C'est ce qu'on appelle souvent l'idiome RAII (l'acquisition de ressources est l'initialisation).
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. }
la source
Cleaner cleaner();
Je pense que ce sera une déclaration de fonction plutôt qu'une définition d'objet.Cleaner cleaner;
ouCleaner cleaner{};
.Eh bien, au fond, pourquoi pas? A
struct
en C (remontant à la nuit des temps) n'était qu'un moyen de déclarer une structure d'enregistrement. Si vous en voulez un, pourquoi ne pas pouvoir le déclarer là où vous déclareriez une simple variable?Une fois que vous avez fait cela, rappelez-vous que l'un des objectifs de C ++ était d'être compatible avec C si possible. Alors ça est resté.
la source
Il est mentionné, par exemple, à la section "7.8: Classes locales: classes à l'intérieur des fonctions" de http://www.icce.rug.nl/documents/cplusplus/cplusplus07.html qui l'appelle une "classe locale" et le dit " peut être très utile dans les applications avancées impliquant l'héritage ou des modèles ».
la source
C'est pour créer des tableaux d'objets correctement initialisés.
J'ai une classe C qui n'a pas de constructeur par défaut. Je veux un tableau d'objets de la classe C.Je comprends comment je veux que ces objets soient initialisés, puis dérive une classe D de C avec une méthode statique qui fournit l'argument pour le C dans le constructeur par défaut 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; }
Par souci de simplicité, cet exemple utilise un constructeur trivial non par défaut et un cas où les valeurs sont connues au moment de la compilation. Il est simple d'étendre cette technique aux cas où vous souhaitez qu'un tableau d'objets soit initialisé avec des valeurs connues uniquement à l'exécution.
la source
D*
paramètre), cela se cassera silencieusement si D est en fait plus grand que C . (Je pense ...)