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

222
15 августа 2017, 15:37

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

Answer 1

Вызывать подобным образом методы приходится ровно в том случае, если Вы сохранили указатель на этот метод :) Как это работает, описал @Harry, а вот зачем - это хороший вопрос.

Нередко возникает ситуация, когда программисты хотят упростить себе жизнь (ленивые же). Написали Вы, например, такой код:

#include <iostream>
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, std::string> 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, void(A::*)()> 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ов быстрее будет вариант с вектором или первоначальный, но данный пример для академических целей.

Answer 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);
}  

Рабочий пример тут.

READ ALSO
&ldquo;Ошибка конвертации&rdquo; в C/C++ [требует правки]

“Ошибка конвертации” в C/C++ [требует правки]

ЗдравствуйтеКто знает, почему в этом проэкте две ошибки? "invalid conversion from 'int()(const char)' to 'const void*' [-fpermissive]"

254
Утечка памяти в функции с++

Утечка памяти в функции с++

Есть такое задание :

229
Проблема с создание вектора в классе, С++

Проблема с создание вектора в классе, С++

Я создаю вектор ссылок на объекты моего класса в главной функции - всё работает замечательноСоздаю схожий вектор в ином классе - всё работать...

199
Считывание экрана окна с помощью opencv и С++ [требует правки]

Считывание экрана окна с помощью opencv и С++ [требует правки]

Как это правильно реализовать, чтобы захват был в Mat?

235