Я просто по ошибке сделал что-то подобное на C ++, и это работает. Почему я могу это сделать?
int main(int argc, char** argv) {
struct MyStruct
{
int somevalue;
};
MyStruct s;
s.somevalue = 5;
}
Теперь, сделав это, я как бы вспомнил, что читал где-то об этом трюке давным-давно, как об инструменте функционального программирования для бедняков на C ++, но я не могу вспомнить, почему это действительно так и где я его читал.
Ответы на любой вопрос приветствуются!
Примечание: хотя при написании вопроса я не получил ссылок на этот вопрос. , текущая боковая панель указывает на это, поэтому я помещу его здесь для справки, в любом случае вопрос другой, но может быть полезен.
c++
data-structures
functional-programming
Роберт Гулд
источник
источник
Ответы:
[РЕДАКТИРОВАТЬ 18/4/2013]: К счастью, упомянутые ниже ограничения были сняты в C ++ 11, поэтому локально определенные классы в конце концов полезны! Спасибо комментатору bamboon.
Возможность определять классы локально бы сделать создание пользовательских функторов (классов с
operator()()
, например , функцией сравнения для перехода кstd::sort()
или «петлевым телам» , которые будут использоваться сstd::for_each()
) гораздо более удобным.К сожалению, C ++ запрещает использование локально определенных классов с шаблонами , так как они не связаны. Поскольку большинство приложений функторов включают типы шаблонов, которые созданы на основе типа функтора, локально определенные классы не могут использоваться для этого - вы должны определять их вне функции. :(
[РЕДАКТИРОВАТЬ 1/11/2009]
Соответствующая цитата из стандарта:
источник
Одно приложение локально определенных классов C ++ находится в шаблоне проектирования 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; }
Хотя вы можете сделать то же самое с анонимным пространством имен.
источник
На самом деле это очень полезно для выполнения некоторой работы по обеспечению безопасности исключений на основе стека. Или общая очистка от функции с несколькими точками возврата. Это часто называют идиомой RAII (получение ресурсов - инициализация).
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. }
источник
Cleaner cleaner();
Думаю, это будет объявление функции, а не определение объекта.Cleaner cleaner;
илиCleaner cleaner{};
.Ну в принципе, а почему бы и нет? A
struct
в C (восходящий к истокам времен) был просто способом объявить структуру записи. Если он вам нужен, почему бы не объявить его там, где вы бы объявили простую переменную?Как только вы это сделаете, помните, что цель C ++ - быть совместимой с C, если это вообще возможно. Так оно и осталось.
источник
Он упоминается, например, в разделе «7.8: Локальные классы: классы внутри функций» http://www.icce.rug.nl/documents/cplusplus/cplusplus07.html, который называет его «локальным классом» и говорит: « может быть очень полезен в сложных приложениях, включающих наследование или шаблоны ».
источник
Это для создания массивов объектов, которые правильно инициализированы.
У меня есть класс C, у которого нет конструктора по умолчанию. Мне нужен массив объектов класса C. Я выясняю, как я хочу инициализировать эти объекты, затем получаю класс D из C с помощью статического метода, который предоставляет аргумент для C в конструкторе по умолчанию в 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; }
Для простоты в этом примере используется тривиальный конструктор не по умолчанию и случай, когда значения известны во время компиляции. Этот метод легко распространить на случаи, когда вы хотите, чтобы массив объектов был инициализирован значениями, которые известны только во время выполнения.
источник
D*
параметр), тогда это будет молча сломаться, если D на самом деле больше, чем C . (Я думаю ...)