[c++] सी ++: कक्षा डेटा सदस्य के सूचक ":: *"



Answers

यह सबसे सरल उदाहरण है जिसके बारे में मैं सोच सकता हूं कि दुर्लभ मामलों को बताता है जहां यह सुविधा प्रासंगिक है:

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

यहां ध्यान देने योग्य बात यह है कि पॉइंटर count_fruit में पास हो गया है। यह आपको अलग count_apples और count_oranges फ़ंक्शन लिखने के लिए सहेजता है।

Question

मैं इस अजीब कोड स्निपेट में आया जो ठीक से संकलित करता है:

class Car
{
    public:
    int speed;
};

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

C ++ में इस पॉइंटर को कक्षा के गैर-स्थैतिक डेटा सदस्य के पास क्यों है? वास्तविक कोड में इस अजीब सूचक का उपयोग क्या है?




बाद में आप किसी भी उदाहरण पर इस सदस्य तक पहुंच सकते हैं:

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

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

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

  return 0;
}

ध्यान दें कि आपको इसे कॉल करने के लिए एक उदाहरण की आवश्यकता है, इसलिए यह एक प्रतिनिधि की तरह काम नहीं करता है।
इसका शायद ही कभी उपयोग किया जाता है, मुझे अपने पूरे वर्षों में एक या दो बार इसकी आवश्यकता है।

आम तौर पर एक इंटरफ़ेस (यानी सी ++ में शुद्ध बेस क्लास) का उपयोग करना बेहतर डिज़ाइन विकल्प है।




आप दोहरी, नामांकित सदस्य (iexdata) और सरणी-सबस्क्रिप्ट (यानी 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;
}



मान लीजिए कि आपके पास संरचना है। उस संरचना के अंदर * कुछ प्रकार का नाम * एक ही प्रकार के दो चर हैं लेकिन विभिन्न अर्थों के साथ

struct foo {
    std::string a;
    std::string b;
};

ठीक है, अब मान लें कि आपके पास एक कंटेनर में foo s का एक गुच्छा है:

// key: some sort of name, value: a foo instance
std::map<std::string, foo> container;

ठीक है, अब मान लें कि आप अलग-अलग स्रोतों से डेटा लोड करते हैं, लेकिन डेटा एक ही फैशन में प्रस्तुत किया जाता है (उदाहरण के लिए, आपको एक ही पार्सिंग विधि की आवश्यकता है)।

आप ऐसा कुछ कर सकते हैं:

void readDataFromText(std::istream & input, std::map<std::string, foo> & container, std::string foo::*storage) {
    std::string line, name, value;

    // while lines are successfully retrieved
    while (std::getline(input, line)) {
        std::stringstream linestr(line);
        if ( line.empty() ) {
            continue;
        }

        // retrieve name and value
        linestr >> name >> value;

        // store value into correct storage, whichever one is correct
        container[name].*storage = value;
    }
}

std::map<std::string, foo> readValues() {
    std::map<std::string, foo> foos;

    std::ifstream a("input-a");
    readDataFromText(a, foos, &foo::a);
    std::ifstream b("input-b");
    readDataFromText(b, foos, &foo::b);
    return foos;
}

इस बिंदु पर, readValues() को कॉल करने से "इनपुट-ए" और "इनपुट-बी" के एकजुट होने के साथ एक कंटेनर वापस आ जाएगा; सभी चाबियाँ मौजूद होंगी, और इनमें से एक या बी या दोनों के साथ फूज़ होगा।




मुझे लगता है कि आप केवल यह करना चाहते हैं यदि सदस्य डेटा बहुत बड़ा था (उदाहरण के लिए, एक और सुंदर भारी वर्ग का एक वस्तु), और आपके पास कुछ बाहरी दिनचर्या है जो केवल उस वर्ग की वस्तुओं के संदर्भों पर काम करती है। आप सदस्य ऑब्जेक्ट की प्रतिलिपि नहीं बनाना चाहते हैं, इसलिए इससे आप इसे पास कर सकते हैं।




IBM पास इसका उपयोग करने के तरीके पर कुछ और दस्तावेज हैं। संक्षेप में, आप कक्षा में ऑफसेट के रूप में पॉइंटर का उपयोग कर रहे हैं। आप इन पॉइंटर्स का उपयोग उस कक्षा से अलग नहीं कर सकते जो वे संदर्भित करते हैं, इसलिए:

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

यह थोड़ा अस्पष्ट लगता है, लेकिन एक संभावित अनुप्रयोग यह है कि यदि आप जेनेरिक डेटा को कई अलग-अलग ऑब्जेक्ट प्रकारों में deserializing के लिए कोड लिखने की कोशिश कर रहे हैं, और आपके कोड को ऑब्जेक्ट प्रकारों को संभालने की आवश्यकता है जो इसे बिल्कुल कुछ नहीं जानता (उदाहरण के लिए, आपका कोड है एक पुस्तकालय में, और जिन वस्तुओं में आप deserialize वे पुस्तकालय के उपयोगकर्ता द्वारा बनाया गया था)। सदस्य पॉइंटर्स आपको व्यक्तिगत डेटा सदस्य ऑफ़सेट का जिक्र करने का एक सामान्य, अर्ध-सुगम तरीका प्रदान करते हैं, बिना टाइपलेस शून्य * का उपयोग किए बिना सी स्ट्रक्चर के लिए आप जिस तरह से प्रयास कर सकते हैं।




Related