Eu simplesmente fiz algo assim em C ++ por engano e funciona. Por que posso fazer isso?
int main(int argc, char** argv) {
struct MyStruct
{
int somevalue;
};
MyStruct s;
s.somevalue = 5;
}
Depois de fazer isso, meio que me lembrei de ter lido sobre esse truque em algum lugar, há muito tempo, como uma espécie de ferramenta de programação funcional para C ++, mas não consigo me lembrar por que isso é válido, ou onde eu li.
As respostas a qualquer uma das perguntas são bem-vindas!
Nota: Embora ao escrever a pergunta eu não tenha obtido nenhuma referência a esta pergunta , a barra lateral atual indica isso, então irei colocá-la aqui para referência, de qualquer forma a pergunta é diferente, mas pode ser útil.
c++
data-structures
functional-programming
Robert Gould
fonte
fonte
Respostas:
[EDITAR 18/4/2013]: Felizmente, a restrição mencionada abaixo foi removida no C ++ 11, portanto, as classes definidas localmente são úteis, afinal! Graças ao comentarista bamboon.
A capacidade de definir classes localmente tornaria a criação de functores personalizados (classes com
operator()()
, por exemplo, funções de comparação para passar parastd::sort()
ou "corpos de loop" para serem usadosstd::for_each()
) muito mais conveniente.Infelizmente, C ++ proíbe o uso de classes definidas localmente com modelos , pois eles não têm ligação. Uma vez que a maioria dos aplicativos de functores envolvem tipos de template que são modelados no tipo de functor, classes definidas localmente não podem ser usadas para isso - você deve defini-las fora da função. :(
[EDITAR 11/01/2009]
A citação relevante do padrão é:
fonte
Uma aplicação de classes C ++ definidas localmente é no padrão de design 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; }
Embora você possa fazer o mesmo com o namespace anônimo.
fonte
Na verdade, é muito útil para fazer algum trabalho de segurança de exceção baseado em pilha. Ou limpeza geral de uma função com vários pontos de retorno. Isso é freqüentemente chamado de idioma RAII (aquisição de recursos é inicialização).
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. }
fonte
Cleaner cleaner();
Acho que isso será uma declaração de função, em vez de uma definição de objeto.Cleaner cleaner;
ouCleaner cleaner{};
.Bem, basicamente, por que não? A
struct
em C (voltando ao início dos tempos) era apenas uma forma de declarar uma estrutura de registro. Se você quiser um, por que não poder declará-lo onde declararia uma variável simples?Depois de fazer isso, lembre-se de que o objetivo de C ++ era ser compatível com C, se possível. Então ficou.
fonte
É mencionado, por exemplo, na seção "7.8: Classes locais: classes dentro de funções" de http://www.icce.rug.nl/documents/cplusplus/cplusplus07.html que a chama de "classe local" e diz isso " pode ser muito útil em aplicativos avançados que envolvem herança ou modelos ".
fonte
É para criar matrizes de objetos que são inicializados corretamente.
Eu tenho uma classe C que não tem construtor padrão. Quero um array de objetos da classe C. Descubro como quero esses objetos inicializados e, em seguida, derivar uma classe D de C com um método estático que fornece o argumento para o C no construtor padrão 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; }
Para fins de simplicidade, este exemplo usa um construtor não padrão trivial e um caso em que os valores são conhecidos em tempo de compilação. É simples estender essa técnica aos casos em que você deseja uma matriz de objetos inicializada com valores que são conhecidos apenas em tempo de execução.
fonte
D*
recebe um parâmetro), então isso será interrompido silenciosamente se D for realmente maior que C . (Eu acho ...)