Указатель на элемент данных класса “::*”

Здесь есть одна возможность. Некоторые из предположений в комментариях. Конечно, есть и другие способы сделать это. Размер набора в знаменателе второй формулы можно сделать проще, чем длину набора или списка, но мой способ избегает использования памяти для набора / списка и более согласуется с числителем.

def formula1(X, n, a, b):
    """Return the first formula for matrix X, size n, and indices a and b.
    """
    return sum(X[a][t] - X[b][t] for t in range(1, n+1)) / n

def formula2(X, n, i, j, x, y, a, P):
    """Return the second formula for matrix X, size n, indices i, j, x, and y,
    array or mapping a, array or mapping of sets P.
    """
    numer = sum(abs(X[i][t] - X[j][t])
                for t in range(1, n+1)
                if a[t] in P[x] or a[t] in P[y])
    denom = sum(1
                for t in range(1, n+1)
                if a[t] in P[x] or a[t] in P[y])
    return numer / denom
223
задан L. F. 22 May 2019 в 23:44
поделиться

8 ответов

Это - "указатель на участника" - следующий код иллюстрирует свое использование:

#include <iostream>
using namespace std;

class Car
{
    public:
    int speed;
};

int main()
{
    int Car::*pSpeed = &Car::speed;

    Car c1;
    c1.speed = 1;       // direct access
    cout << "speed is " << c1.speed << endl;
    c1.*pSpeed = 2;     // access via pointer to member
    cout << "speed is " << c1.speed << endl;
    return 0;
}

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

Редактирование: я не могу думать бесцеремонно об убедительном использовании для указателей на членские данные. Указатель на функции членства может использоваться в сменной архитектуре, но еще раз создание примера в небольшом пространстве побеждает меня. Следующее является моей лучшей (непротестированной) попыткой - Применять функция, которая сделала бы некоторых пред & сообщение, обрабатывающее прежде, чем применить выбранную пользователями функцию членства к объекту:

void Apply( SomeClass * c, void (SomeClass::*func)() ) {
    // do hefty pre-call processing
    (c->*func)();  // call user specified function
    // do hefty post-call processing
}

круглые скобки приблизительно c->*func необходимы, потому что ->* оператор имеет более низкий приоритет, чем оператор вызова функции.

175
ответ дан Oktalist 23 November 2019 в 04:00
поделиться

Я думаю, что Вы только хотели бы сделать это, если бы членские данные были довольно большими (например, объект другого довольно значительного класса), и у Вас есть некоторая внешняя подпрограмма, которая только работает над ссылками на объекты того класса. Вы не хотите копировать членский объект, таким образом, это позволяет Вам раздать его.

0
ответ дан Andrew Jaffe 23 November 2019 в 04:00
поделиться

Можно использовать массив указателя на (гомогенные) членские данные для включения двойного, именованный участник (т.е. x.data) и нижний индекс массива (т.е. x [idx]) интерфейс.

#include <cassert>
#include <cstddef>

struct vector3 {
    float x;
    float y;
    float z;

    float& operator[](std::size_t idx) {
        static float vector3::*component[3] = {
            &vector3::x, &vector3::y, &vector3::z
        };
        return this->*component[idx];
    }
};

int main()
{
    vector3 v = { 0.0f, 1.0f, 2.0f };

    assert(&v[0] == &v.x);
    assert(&v[1] == &v.y);
    assert(&v[2] == &v.z);

    for (std::size_t i = 0; i < 3; ++i) {
        v[i] += 1.0f;
    }

    assert(v.x == 1.0f);
    assert(v.y == 2.0f);
    assert(v.z == 3.0f);

    return 0;
}
10
ответ дан Functastic 23 November 2019 в 04:00
поделиться

Одним путем я использовал его, то, если у меня есть две реализации того, как сделать что-то в классе, и я хочу выбрать один во времени выполнения, не имея необходимость постоянно проходить, если оператор т.е.

class Algorithm
{
public:
    Algorithm() : m_impFn( &Algorithm::implementationA ) {}
    void frequentlyCalled()
    {
        // Avoid if ( using A ) else if ( using B ) type of thing
        (this->*m_impFn)();
    }
private:
    void implementationA() { /*...*/ }
    void implementationB() { /*...*/ }

    typedef void ( Algorithm::*IMP_FN ) ();
    IMP_FN m_impFn;
};

, Очевидно, это только практически полезно, если Вы чувствуете, что код куется достаточно, что, если оператор замедляет вещи, сделанные, например, глубокие в кишках некоторого интенсивного алгоритма где-нибудь. Я все еще думаю, что это более изящно, чем, если оператор даже в ситуациях, где это не имеет никакого практического применения, но это - просто мой opnion.

2
ответ дан Troubadour 23 November 2019 в 04:00
поделиться

IBM имеет еще некоторую документацию относительно того, как использовать это. Кратко, Вы используете указатель в качестве смещения в класс. Вы не можете использовать эти указатели кроме класса, который они отсылают к, таким образом:

  int Car::*pSpeed = &Car::speed;
  Car mycar;
  mycar.*pSpeed = 65;

Это кажется немногим неясным, но одно возможное приложение - то, при попытке написать код для десериализации универсальных данных во многие различные типы объектов, и Ваш код должен обработать типы объектов, о которых это абсолютно ничего не знает (например, Ваш код находится в библиотеке, и объекты, в которые Вы десериализовываете, были созданы пользователем Вашей библиотеки). Членские указатели дают Вам, универсальный, получеткий способ относиться к отдельным смещениям элемента данных, не имея необходимость обращаться к пустоте без типов * обманывает способ, которым Вы могли бы для структур C.

26
ответ дан AHelps 23 November 2019 в 04:00
поделиться

Можно позже получить доступ к этому участнику, на любой экземпляр:

int main()
{    
  int Car::*pSpeed = &Car::speed;    
  Car myCar;
  Car yourCar;

  int mySpeed = myCar.*pSpeed;
  int yourSpeed = yourCar.*pSpeed;

  assert(mySpeed > yourSpeed); // ;-)

  return 0;
}

Примечание, что Вам действительно нужен экземпляр для обращения к нему, таким образом, это не работает как делегат.
Это редко используется, мне был нужен он, возможно, несколько раз во всех моих годах.

Обычно использование интерфейса (т.е. чистый базовый класс в C++) является лучшим проектным решением.

35
ответ дан peterchen 23 November 2019 в 04:00
поделиться

Другое приложение является навязчивыми списками. Тип элемента может сказать список, каковы его следующие/предыдущие указатели. Таким образом, список не использует трудно кодированные имена, но может все еще использовать существующие указатели:

// say this is some existing structure. And we want to use
// a list. We can tell it that the next pointer
// is apple::next.
struct apple {
    int data;
    apple * next;
};

// simple example of a minimal intrusive list. Could specify the
// member pointer as template argument too, if we wanted:
// template<typename E, E *E::*next_ptr>
template<typename E>
struct List {
    List(E *E::*next_ptr):head(0), next_ptr(next_ptr) { }

    void add(E &e) {
        // access its next pointer by the member pointer
        e.*next_ptr = head;
        head = &e;
    }

    E * head;
    E *E::*next_ptr;
};

int main() {
    List<apple> lst(&apple::next);

    apple a;
    lst.add(a);
}
58
ответ дан Johannes Schaub - litb 23 November 2019 в 04:00
поделиться

Это позволяет связать членские переменные и функции универсальным способом. Следующее является примером с Вашим Автомобильным классом. Более общее использование связало бы std::pair::first и ::second при использовании в алгоритмах STL и Повышении на карте.

#include <list>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>


class Car {
public:
    Car(int s): speed(s) {}
    void drive() {
        std::cout << "Driving at " << speed << " km/h" << std::endl;
    }
    int speed;
};

int main() {

    using namespace std;
    using namespace boost::lambda;

    list<Car> l;
    l.push_back(Car(10));
    l.push_back(Car(140));
    l.push_back(Car(130));
    l.push_back(Car(60));

    // Speeding cars
    list<Car> s;

    // Binding a value to a member variable.
    // Find all cars with speed over 60 km/h.
    remove_copy_if(l.begin(), l.end(),
                   back_inserter(s),
                   bind(&Car::speed, _1) <= 60);

    // Binding a value to a member function.
    // Call a function on each car.
    for_each(s.begin(), s.end(), bind(&Car::drive, _1));

    return 0;
}
19
ответ дан Alex B 23 November 2019 в 04:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: