Pointer to class data member “::*”

后端 未结 15 1642
清歌不尽
清歌不尽 2020-11-21 11:47

I came across this strange code snippet which compiles fine:

class Car
{
    public:
    int speed;
};

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


        
相关标签:
15条回答
  • 2020-11-21 12:10

    Another application are intrusive lists. The element type can tell the list what its next/prev pointers are. So the list does not use hard-coded names but can still use existing pointers:

    // 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);
    }
    
    0 讨论(0)
  • 2020-11-21 12:10

    One way I've used it is if I have two implementations of how to do something in a class and I want to choose one at run-time without having to continually go through an if statement i.e.

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

    Obviously this is only practically useful if you feel the code is being hammered enough that the if statement is slowing things done eg. deep in the guts of some intensive algorithm somewhere. I still think it's more elegant than the if statement even in situations where it has no practical use but that's just my opnion.

    0 讨论(0)
  • 2020-11-21 12:14

    This is the simplest example I can think of that conveys the rare cases where this feature is pertinent:

    #include <iostream>
    
    class bowl {
    public:
        int apples;
        int oranges;
    };
    
    int count_fruit(bowl * begin, bowl * end, int bowl::*fruit)
    {
        int count = 0;
        for (bowl * iterator = begin; iterator != end; ++ iterator)
            count += iterator->*fruit;
        return count;
    }
    
    int main()
    {
        bowl bowls[2] = {
            { 1, 2 },
            { 3, 5 }
        };
        std::cout << "I have " << count_fruit(bowls, bowls + 2, & bowl::apples) << " apples\n";
        std::cout << "I have " << count_fruit(bowls, bowls + 2, & bowl::oranges) << " oranges\n";
        return 0;
    }
    

    The thing to note here is the pointer passed in to count_fruit. This saves you having to write separate count_apples and count_oranges functions.

    0 讨论(0)
  • 2020-11-21 12:20

    You can later access this member, on any instance:

    int main()
    {    
      int Car::*pSpeed = &Car::speed;    
      Car myCar;
      Car yourCar;
    
      int mySpeed = myCar.*pSpeed;
      int yourSpeed = yourCar.*pSpeed;
    
      assert(mySpeed > yourSpeed); // ;-)
    
      return 0;
    }
    

    Note that you do need an instance to call it on, so it does not work like a delegate.
    It is used rarely, I've needed it maybe once or twice in all my years.

    Normally using an interface (i.e. a pure base class in C++) is the better design choice.

    0 讨论(0)
  • 2020-11-21 12:20

    Just to add some use cases for @anon's & @Oktalist's answer, here's a great reading material about pointer-to-member-function and pointer-to-member-data.

    https://www.dre.vanderbilt.edu/~schmidt/PDF/C++-ptmf4.pdf

    0 讨论(0)
  • 2020-11-21 12:23

    It makes it possible to bind member variables and functions in the uniform manner. The following is example with your Car class. More common usage would be binding std::pair::first and ::second when using in STL algorithms and Boost on a map.

    #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;
    }
    
    0 讨论(0)
提交回复
热议问题