Указатель на функцию
тут где-то обсуждалось, что вроде как в С++ это сделать нельзя.
в Pascal-Delphi можно:
в Pascal-Delphi можно:
type
FuncPtr = function (x:integer): Integer;
FuncClsPtr = function (x:integer): Integer of object;
T=class
public
function Z(x:integer):Integer;
end;
...
var
x: FuncPtr;
y: FuncClsPtr;
C: T;
...
begin
x:=C.Z; // нельзя - ошибка компилятора
y:=C.Z; // можно
end.
int (T1::*pint) = &T1::f;
cout << (t->*p5) << endl;
T1 *t = new T1;мне кажется скобки лишние.
class t1 = object
method f x : int = x
end
open Printf
let t = new t1;;
printf "%d\n" (t#f 5);;
let p = t#f;;
printf "%d\n" (p 5);;
что это за язык?
OCaml
Спасибо, . Тогда я правильно понял, что из конструктора подобный указатель вызывается так:
Компилятор не ругается, просто я бы хотел узнать, как это сделать корректно.
#include <iostream>
using namespace std;
class T1 {
public:
int f(int x) {return x;}
T1;
};
T1::T1 {
int (T1::*pint) = &T1::f;
cout << (this->*p4) << endl;
}
int main {
T1 t;
cout << t.f(5) << endl;
return 0;
}
Еще вопрос по теме. Пытаюсь писать такое
При компиляции возникает ошибка:
class A {
public:
virtual void f { }
};
int main
{
A a;
void (A::*p;
p = &a.f;
}
Почему так? Я хочу получить указатель именно на тот f который у объекта. У потомков он может быть переопределен и я хочу получить другое значение.
1.cpp: In function 'int main':
1.cpp:10: error: ISO C++ forbids taking the address of a bound member function to form a pointer to member function. Say '&A::f'
> Почему так? Я хочу получить указатель именно на тот f который у объекта. У потомков он может быть переопределен и я хочу получить другое значение.
Переопределённый метод не будет иметь смысл для объектов типа A,
то есть его нельзя присваивать переменной p.
Переопределённый метод не будет иметь смысл для объектов типа A,
то есть его нельзя присваивать переменной p.
На всякий случай, чтобы все понимали:
class A
{
public:
virtual void m { std::cout << "A::m\n"; }
};
class B : public A
{
public:
virtual void m { std::cout << "B::m\n"; }
};
int main
{
void (A::*p;
p = &A::m;
A a; (a.*p;
B b; (b.*p;
return(0);
}
A::m
B::m
Хм. А как это реализовано?
в указатель номер метода в VMT запихнули
И чё, в рантайме проверять, какого сорта у нас указатель?
Во дела.
Во дела.
это должно на этапе компиляции делаться
PS
PS
18 p = &A::m;
(gdb) next
19 A a; (a.*p;
(gdb) print p
$1 = {__pfn = 0x1, __delta = 0}
>И чё, в рантайме проверять, какого сорта у нас указатель?
>Во дела.
Необязательно. Например, это может быть указатель на генерируемую компилятором вспомогательную функцию, вызывающую функцию с адресом vtable + x (где х - номер метода)
>Во дела.
Необязательно. Например, это может быть указатель на генерируемую компилятором вспомогательную функцию, вызывающую функцию с адресом vtable + x (где х - номер метода)
Ну member-pointer это вообще сложная вещь. Есть даже опции компилятору, например, делать ли у всех классов m-p одного размера или пожадничать и т.д.
И чё, в рантайме проверять, какого сорта у нас указатель?Это что ты имеешь в виду? В рантайме обычный virtual dispatch стоит, а что делать, метод-то виртуальный...
Зачем в рантайме? Все типы известны статически, VMT у потомков до определенного смещения совпадает. А для не потомков операция отсечется еще при компиляции.
gcc походу проверяет в рантайме
Да я чего-то стормозил, действительно непонятно как еще делать.
void call(A & o, void (A::*p
{
(o.*p;
}
Нужна же развилка, указатель на виртуальную функцию или не на виртуальную.
.type _Z4callR1AMS_FvvE, @function
_Z4callR1AMS_FvvE:
.LFB1521:
pushl %ebp
.LCFI0:
movl %esp, %ebp
.LCFI1:
subl $24, %esp
.LCFI2:
movl 12(%ebp %eax
movl 16(%ebp %edx
movl %eax, -8(%ebp)
movl %edx, -4(%ebp)
movzbl -8(%ebp %eax
xorb $1, %al
andb $1, %al
testb %al, %al
je .L2
movl -8(%ebp %eax
movl %eax, -12(%ebp)
jmp .L3
.L2:
movl -4(%ebp %eax
movl 8(%ebp %edx
addl %eax, %edx
movl -8(%ebp %eax
addl (%edx %eax
decl %eax
movl (%eax %eax
movl %eax, -12(%ebp)
.L3:
movl -4(%ebp %eax
addl 8(%ebp %eax
movl %eax, (%esp)
call *-12(%ebp)
leave
ret
В MSVC это устроено так:
А по адресу, куда делается джамп, лежит заранее сгенерённый стаб, вызывающий нужный метод
void call(A & o, void (A::*p
{
mov ecx, dword ptr [esp+4]
jmp dword ptr [esp+8]
А по адресу, куда делается джамп, лежит заранее сгенерённый стаб, вызывающий нужный метод
Вызов нестатической функции-члена класса отличается от вызова обычной функции. Отличие заключается в том, что при вызове функции-члена ей помимо явно задаваемых параметров, неявно передаётся указатель this. Фактически у функций-членов на один параметр больше, чем описано в заголовке.
class C
{
public:
void f (int x);
};
void (*pf) (int x); // Указатель на функцию одного параметра
void (C::*pcf) (int x); // Указатель на функцию двух параметров, один из которых неявный
void g (void)
{
pf = &C::f; // Неверно
pcf = &C::f; // Верно
}
Оставить комментарий
Jackill
Как получить указатель на функцию-член класса? Другими словами, почему этот кодне компилируется, в то время как этот
работает. В первом случае компилятор ругается так: