Одна вещь, которую я нахожу наиболее раздражающей в ООП, состоит в том, что всякий раз, когда вам нужна новая переменная в функции-члене, и вам нужно, чтобы эта переменная «присоединяла» объект, к которому вызывается эта функция, у вас, по сути, нет выбора, кроме создания нового частного поле. На мой взгляд, это уродливо, потому что это означает, что переменная инициализируется при создании объекта (и вы, возможно, никогда не сможете использовать ее, если не вызываете метод, который нуждается в этом), она не скрыта от других объектов, которые могут получить доступ к закрытым членам объекта, и, кроме того, это может помешать определению вашего класса (подумайте о классах C ++, которые чаще всего поставляются с заголовком с полным определением полей в нем).
Говоря на языке C ++, я хочу, чтобы поведение static
модификатор для переменной в глобальной функции, но в функциях-членах, и хранилище должно быть в объекте.
Я не знаю так много языков, но у меня есть ощущение, что в динамических языках программирования это проще сделать. Я могу думать о Lua: я бы просто добавил новый индекс в текущей таблице. Это не скрывает новое «поле» от остального мира, но если вы не вмешаетесь в метатабельность, все в Lua является общедоступным, поэтому на самом деле это не проблема в мышлении Lua. Но проблема инициализации решена.
Итак, мой вопрос: существует ли какой-либо статический язык программирования (т. Е. Тот, на котором макет объекта известен во время компиляции), где это возможно?
И, между прочим, есть ли аккуратный обходной путь в C ++ для получения аналогичного результата?
Поскольку общая идея объектно-ориентированного программирования состоит в том, чтобы инкапсулировать поведение как задавать методов (функций) и данных как задавать для переменных экземпляра, такого поведения нет ни в одном статическом языке программирования, о котором я могу думать.
Однако идея разделить задачи одного класса на несколько единиц (чтобы сделать его менее монолитным) рассматривалась на нескольких языках. Идея состоит в том, чтобы отделить различные проблемы в пределах одного класса объекта. Хотя переменная не создается во время выполнения (это делает тип не статичным), она может быть объявлена в модуле отдельно от других модулей.
Это на самом деле вроде доступно в C #. Хотя реализация является чисто косметической, вы можете объявить один класс как несколько частичных классов. Одним из преимуществ является разделение задач, чтобы избежать единого большого объявления всего, что инкапсулировано классом (другое использование — сценарии генерации кода).
Это позволяет вам сделать следующее:
File1:
partial class Foo {
int X;
void DoSomethingWithX() {
X++;
}
}
Файл 2:
partial class Foo {
int Y;
void DoSomethingWithY() {
Y++;
}
}
Ты говоришь static
и по замыслу в static
Языки каждая вещь в дизайне объекта должна быть рассмотрена во время компиляции, и класс не может изменить это сам во время выполнения. Так что я не думаю, что static
язык может сделать такой dynamic
работа, и это хорошо, так как это снизит производительность, когда вы обращаетесь к переменной, в static
Компилятор языков создает код для доступа к этой переменной во время компиляции, но если такая переменная (function-object-static) существует, то компилятор должен написать дополнительный код для проверки некоторого динамического хранилища, чтобы увидеть, существует ли свойство с таким именем или нет, и это только потому, что тебе грустно от нынешнего дизайна C ++ !? Но с другой стороны, если вы не хотите делать это без изменения полей, вы можете просто добавить одну дополнительную переменную в класс типа, который может использоваться для динамического поиска (например, std::map
) и сделать эту переменную private
так что никто кроме вас в вашем классе не может получить к нему доступ:
class foo {
std::map<std::string, boost::any> functionVariables;
public:
void test1() {
int visitNumber;
auto i = functionVariables.find( "test1" );
if( i == functionVariables.end() ) {
// This is first visit of the function, initialize your variable
functionVariables["test1"] = (visitNumber = 0);
} else {
// It is already initialized, use it
visitNumber = ++ *boost::any_cast<int>(&*i);
}
}
};