Страницы

Поиск по вопросам

вторник, 31 декабря 2019 г.

Доступ к членам класса через .* и ->*

#cpp


В каких случаях используются операторы x.*ptm или p->*ptm? Прошу привести минимальный
пример, где это может понадобиться. Да и вообще, где это реально может пригодится.
Стоит ли использовать их? Можно ли их чем нибудь заменить?
    


Ответы

Ответ 1



Вызывать подобным образом методы приходится ровно в том случае, если Вы сохранили указатель на этот метод :) Как это работает, описал @Harry, а вот зачем - это хороший вопрос. Нередко возникает ситуация, когда программисты хотят упростить себе жизнь (ленивые же). Написали Вы, например, такой код: #include enum class State { One, Two, Three }; class A { State _cur_state; public: A(State s) : _cur_state(s) {} void DoSomething() { switch (_cur_state) { case State::One: std::cout << "Foo" << std::endl; break; case State::Two: std::cout << "Bar" << std::endl; break; case State::Three: std::cout << "Baz" << std::endl; break; } }; }; int main() { A(State::One).DoSomething(); } Через некоторое время придёт осознание того, что проще-таки написать class A { State _cur_state; public: A(State s) : _cur_state(s) {} void DoSomething() { static std::unordered_map state_to_string { { State::One, "Foo" }, { State::Two, "Bar" }, { State::Three, "Baz" } }; std::cout << state_to_string[_cur_state] << std::endl; }; }; Через некоторое время оказывается, что в caseах должен быть какой-то замудреный код и Вы возвращаетесь к первоначальному варианту, переместив этот код в методы: class A { State _cur_state; void DoFoo() { /* code */ } void DoBar() { /* code */ } void DoBaz() { /* code */ } public: A(State s) : _cur_state(s) {} void DoSomething() { switch (_cur_state) { case State::One: DoFoo(); break; case State::Two: DoBar(); break; case State::Three: DoBaz(); break; } }; }; Но потом Вы вспоминаете про указатели на методы и код вновь становится чистым! class A { State _cur_state; void DoFoo() { /* code */ } void DoBar() { /* code */ } void DoBaz() { /* code */ } public: A(State s) : _cur_state(s) {} void DoSomething() { static std::unordered_map state_to_method { { State::One, &A::DoFoo }, { State::Two, &A::DoBar }, { State::Three, &A::DoBaz } }; (this->*state_to_method[_cur_state])(); }; }; P.S. Обработку ошибок не писал. P.P.S. В случае enumов быстрее будет вариант с вектором или первоначальный, но данный пример для академических целей.

Ответ 2



Ну, например, у вас есть функция, которая должна вызвать определенную функцию-член определенного объекта - все определяется во время работы. class Test { int m; public: Test(int i = 0):m(i){} void func1() const { cout << "Test::func1, m = " << m << "\n"; } void func2() const { cout << "Test::func2, m = " << m << "\n"; } }; // Тип testfunc - указатель на функцию-член Test typedef void (Test::*testfunc)() const; // Вызов для объекта Test функции f void out(const Test& t, testfunc f) { (t.*f)(); } // То же через указатель void outPtr(const Test* t, testfunc f) { (t->*f)(); } int main() { Test a(1), b(2); out(a,&Test::func1); out(b,&Test::func2); outPtr(&a,&Test::func2); outPtr(&b,&Test::func1); } Рабочий пример тут.

Комментариев нет:

Отправить комментарий