=== Wskaźnik na metodą z klasy ===
QLineEdit * le = new QLineEdit;
// wskaźnik na funkcję z klasy:
void (QLineEdit::*leMethod1) () = &QLineEdit::clear;
// wywołanie takiego wskaźnika na rzeczy obiektu le:
(le->*leMethod1)();
// to samo, z argumentem:
void (QLineEdit::*leMethod2) (bool) = &QLineEdit::setEnabled;
(le->*leMethod2)(true);
Wyjaśnienie:
* '' (*) ()'', np: ''void (*) (int)'' ← typ dla zwykłej funkcji
* '' (::*) ()'', np: ''void (A::*) (int)'' ← typ dla metody z obiektu
* '' (::*nazwa) ()'', np: ''void (A::*m) (int)'' ← zmienna powyższego typu
* dla zwykłych (nie wirtualnych) metod kompilator wyznacza którą metodę (znajdującą się pod znanym na etapie kompilacji adresem) ma wywołać na rzecz obiektu.
* dla wirtualnych metod kompilator wylicza pozycję w [[https://en.wikipedia.org/wiki/Virtual_method_table|tabeli metod wirtualnych]] którą należy wywołać.
=== Ręczne połączenie metody z obiektem ===
template
struct opakowanie {
T * obiekt;
void (T::*metoda) (bool);
void operator()(bool arg){
(obiekt->*metoda)(arg);
}
};
void someCode(){
QLineEdit * le = new QLineEdit;
opakowanie box {le, &QLineEdit::setEnabled};
box(true);
}
=== Bind - połączenie metody na rzecz obiektu ===
#include
void someCode(){
QLineEdit * le = new QLineEdit;
auto box = std::bind(&QLineEdit::setEnabled, le, std::placeholders::_1);
box(true);
std::function func = std::bind(&QLineEdit::setEnabled, le, std::placeholders::_1);
func(true);
// box i func są różnych typów (func opakowuje box)
}
Formalnie bind to [[https://en.wikipedia.org/wiki/Partial_application|częściowe wykonanie]] metody\\
Dostępny w boost (''boost::bind'') od 2001 roku, włączony w standard C++11
W środku std::bind w GCC działa podobnie jak powyższy przykład; identyfikacja typu przez gdb:
(gdb) ptype box
type = struct std::_Bind(QLineEdit*, std::_Placeholder<1>)> [with _Signature = std::_Mem_fn (QLineEdit *, std::_Placeholder<1>)] : public std::_Weak_result_type > {
private:
std::_Mem_fn _M_f;
std::tuple > _M_bound_args;
public:
_Bind(const std::_Bind(QLineEdit*, std::_Placeholder<1>)> &);
_Bind();
void operator()();
void _Bind const&>(, QLineEdit *&, const std::_Placeholder<1> &);
private:
void __call(, std::_Index_tuple<0ul, 1ul>);
}
=== Bind z ustalenie wartości części argumentów (bez metody z obiektu): ===
#include
#include
using namespace std::placeholders;
void someCode(){
char buf[255];
std::function simpleRead = std::bind(read, std::placeholders::_1, buf, 255);
simpleRead(0);
std::function stdinRead = std::bind(read, 0, std::placeholders::_1, std::placeholders::_2);
stdinRead(buf, 255);
}
Argumenty można podawać przez wartość lub jako referencja opakowane w ''std::ref'' / ''std::cref''.
=== Dlaczego connect był złym przykładem na wskaźnik do funkcji z klasy: ===
QLineEdit *le = new QLineEdit;
// 1) stara składnia connect jest static, nie ma potrzeby definiowania wskaźnika na metodę z klasy:
QMetaObject::Connection (*method1) (const QObject *, const char *, const QObject *, const char *, Qt::ConnectionType) = &QObject::connect;
method1(le, SIGNAL(returnPressed()), le, SLOT(clear()), Qt::AutoConnection);
// 2) nowa składnia poza tym ze też jest static, to jest oparta na template'ach, więc trzeba jakiś zrealizować:
QMetaObject::Connection (*method2) (const QLineEdit *, void (QLineEdit::*)(), const QLineEdit *, void (QLineEdit::*)(), Qt::ConnectionType) = &QObject::connect;
method2(le, &QLineEdit::returnPressed, le, &QLineEdit::clear, Qt::AutoConnection);
// 3) lepiej to wygląda z typedef:
typedef QMetaObject::Connection (*newtype) (const QLineEdit *, void (QLineEdit::*)(), const QLineEdit *, void (QLineEdit::*)(), Qt::ConnectionType);
newtype method3 = &QObject::connect;
method3(le, &QLineEdit::returnPressed, le, &QLineEdit::clear, Qt::AutoConnection);