Я использую парадигму псевдо-операции с простым c и хотел бы, чтобы указатель функции структуры имел доступ к остальным данным структуры.
Единственный способ сделать это - передать ссылку «текущий объект» в каждую функцию, например
struct MyStructure{
//NOTE I want to access this member:
struct MyStructure *self;
int var1;
int var2;
void ( *initMemberFn )(MyStructure *self, int arg1, int arg2);
void ( *memberFn1 )(MyStructure *self);
};
void initMemberFn(MyStructure *self, int arg1, int arg2){
(*self).var1 = arg1;
(*self).var2 = arg2;
}
void memberFn1(MyStructure *self){
//NOTE Access the above member HERE without passing the self argument
printf("var1:%d, var2:%d", (*self).var1, (*self).var2 );
}
int main(){
MyStructure mystruct;
mystruct.self = &mystruct;
mystruct.initMemberFn = &initMemberFn;
mystruct.memberFn1 = &memberFn1;
mystruct.initMemberFn(mystruct.self, 1, 2);
mystruct.memberFn1(mystruct.self);
}
Отмечу, что это работает не на всех компиляторах, но я использую cl.exe Visual Studio.
Есть ли какой-либо (другой) способ получить доступ к самому члену структуры изнутри одной из функций?
(Я отметил соответствующие строки с комментариями.)
Добавить (*self).self = self;
к initMemberFn()
?
Обычный способ — передать &mystruct
напрямую. Я думаю, вы получите отрицательное значение, если в вашей структуре есть поле self
, которое должно совпадать с адресом структуры. Вы можете определить макрос, чтобы избежать двойного указания объекта.
@chux-ReinstateMonica Я попробовал это, это работает для его назначения, но не дает доступа изнутри.
Примечание: в C есть специальный оператор, поэтому вам не нужно писать (*self).var
. Вместо этого используйте self->var
@Verpous Мне придется начать использовать это - я всегда путаю операторы указателей в c
Адрес, хранящийся в mystruct.self = &mystruct;
, будет неверным, если вы присвоите всю структуру, например mystruct1 = mystruct2;
, или передадите структуру по значению функции.
В коде отсутствует определение типа для типа MyStructure
.
Есть ли какой-либо (другой) способ получить доступ к самому члену структуры изнутри одной из функций?
Нет.
В C нет понятия объектных методов, таких как C++ (или другие ООП-языки), есть только глобальные функции.
С точки зрения функции нет self/this и т. д., если вы явно не передадите его как параметр.
Тот факт, что функция вызывается через указатель функции, хранящийся в структуре, не имеет существенного значения.
Как предложено в комментарии, вы можете использовать метку, чтобы сделать звонок немного короче, но это не изменит этот основной факт, а лишь до некоторой степени скроет его (что лично мне кажется менее ясным).
Примечание:
В языках ООП, таких как C++, C# и т. д., на самом деле внутри все будет так же, как и в C, т. е. указатель или ссылка на текущий объект будет передан функции в коде, сгенерированном компилятором.
В известных мне объектно-ориентированных языках это делается путем неявной передачи ссылки на методы экземпляра экземпляра. Например, C++ и Swift передают ссылку на экземпляр в качестве первого параметра в методах экземпляра. Если вы когда-нибудь посмотрите на ассемблерный код, сгенерированный для метода экземпляра, вы это увидите.
Вы не можете сделать это в C, поэтому вам придется передать ссылку явно, как вы это сделали для void memberFn1(MyStructure *self)
.
Что вы подразумеваете под словом неявно? Например, в языке oo есть встроенный макрос?
@ stackoverflow909 Это означает, что обозначение object.method(a,b,c)
является синтаксическим сахаром для вызова method(&object, a,b,c)
(ну, типа того).
@ЕвгенийШ. Да, у меня было ощущение, что это именно так, потому что я думаю, что это... питон? это требует, чтобы вы передали (или определили?) self в качестве параметра для функций-членов.
да, вы можете увидеть подсказки в Python, Rust и тому подобном.
Да, что @EugeneSh. сказал. Большая разница между функциями-членами и другими функциями заключается в том, что первые получают указатель this
в качестве первого параметра, даже если вы не видите его в коде (именно это делает его «неявным»). Компилятор обрабатывает это; вы не видите его как пользователь, но знаете, что можете ссылаться на this
в любой функции-члене.
ООП-компиляторы автоматически делают (почти) именно то, что вы написали, то есть неявно передают указатель this
в качестве первого аргумента. Некоторые компиляторы (в частности, MSVC) передают this
через регистр, даже если все остальные аргументы передаются через стек. Однако точная реализация зависит от компилятора и не предусмотрена спецификацией C++.
Не-ООП-компиляторы, конечно, этого не делают, и вам нужно явно передать все аргументы, включая this
(или self
в вашем примере).
«Почти точно» — потому что нет смысла добавлять член self
в MyStructure
, поскольку он не приносит никакой пользы, а только занимает место в памяти.
«Почти точно» также связано с тем, что языкам ООП не требуется хранить указатели функций методов в объектах.
Для этого вы можете использовать макрос, например
CALL_MEMBER(struct_name, method_name)
. В противном случае нет никакого способа, потому что ваши функции могут вызываться для разных «экземпляров»MyStructure
, и они не смогут узнать, какой из них.