मुझे इस 'पॉइंटर' का स्पष्ट उपयोग कब करना चाहिए?


97

मुझे this->memberकक्षा की एक विधि में स्पष्ट रूप से कब लिखना चाहिए ?


16
मुझे यकीन है कि यह एक डुबकी है, लेकिन यह निश्चित रूप से अप्राप्य है। पहली बार नहीं, काश इस सूचक को स्वयं कहा जाता!

5
इतना ही नहीं, मैं चाहता हूं कि यह एक संदर्भ हो।
rlbond

2
वही। : | यहाँ क्यों, इस तरह से है: research.att.com/~bs/bs_faq2.html#this
GManNickG

11
यदि व्यक्ति जवाब नहीं जानता है तो यह विधि स्पष्ट रूप से काम नहीं करती है।
ASK

3
@ जॉन: एचएम, लगता research.att.com/~bs/है अब है stroustrup.com। नया लिंक: stroustrup.com/bs_faq2.html#this
GManNickG

जवाबों:


118

आमतौर पर, आपके पास नहीं है, this->निहित है।

कभी-कभी, एक नाम अस्पष्टता है, जहां इसका उपयोग कक्षा के सदस्यों और स्थानीय चर को खंडित करने के लिए किया जा सकता है। हालांकि, यहां एक बिल्कुल अलग मामला है जहां this->स्पष्ट रूप से आवश्यक है।

निम्नलिखित कोड पर विचार करें:

template<class T>
struct A {
   int i;
};

template<class T>
struct B : A<T> {

    int foo() {
        return this->i;
    }

};

int main() {
    B<int> b;
    b.foo();
}

यदि आप छोड़ देते हैं this->, तो संकलक को पता नहीं है कि कैसे इलाज करना है i, क्योंकि यह सभी तात्कालिकता में मौजूद हो सकता है या नहीं A। यह बताने के लिए कि iवास्तव में किसी सदस्य के A<T>लिए T, this->उपसर्ग की आवश्यकता है।

नोट: यह अभी भी this->उपसर्ग का उपयोग करके छोड़ना संभव है :

template<class T>
struct B : A<T> {

    using A<T>::i; // explicitly refer to a variable in the base class

    int foo() {
        return i; // i is now known to exist
    }

};

8
घोषणा का उपयोग करने का अच्छा उपयोग :)
फैसल वली

3
यह एक विशेष रूप से बुरा मामला है। मैं इससे पहले काट चुका हूं।
जेसन बेकर

5
यह एक मूर्खतापूर्ण प्रश्न हो सकता है, लेकिन मुझे समझ में नहीं आता कि क्यों iअस्तित्व में नहीं हो सकता है A। क्या मुझे एक उदाहरण मिल सकता है?
कैम जैक्सन

1
@CamJackson मैंने विज़ुअल स्टूडियो पर कोड की कोशिश की। परिणाम वही हैं जो कोई फर्क नहीं पड़ता "यह->" अस्तित्व में है या नहीं। कोई उपाय?
पेंग झांग

8
@CamJackson: कोई भी प्रकार पर कक्षाएं संचालित कर सकता है:template<> struct A<float> { float x; };
Macke

31

यदि आप किसी मौजूदा सदस्य के समान नाम के साथ स्थानीय चर घोषित करते हैं, तो आपको स्थानीय चर के बजाय कक्षा सदस्य तक पहुंचने के लिए इस-> संस्करण का उपयोग करना होगा।

#include <iostream>
using namespace std;
class A
{
    public:
        int a;

        void f() {
            a = 4;
            int a = 5;
            cout << a << endl;
            cout << this->a << endl;
        }
};

int main()
{
    A a;
    a.f();
}

प्रिंट:



1
मैं बेहतर होगा cout << A :: a << एंडल; बजाय। `` यह "इस मामले में महत्वहीन है।
सिद्धान्त 3

3
मैं केवल "m_a" या "a_" जैसे सम्मेलनों के साथ नाम संघर्ष से बचूंगा।
टॉम

19

ऐसे कई कारण हैं जिनकी वजह से आपको thisसूचक को स्पष्ट रूप से उपयोग करने की आवश्यकता हो सकती है ।

  • जब आप किसी फ़ंक्शन के लिए अपनी ऑब्जेक्ट का संदर्भ पास करना चाहते हैं।
  • जब सदस्य ऑब्जेक्ट के समान नाम के साथ स्थानीय रूप से घोषित ऑब्जेक्ट है।
  • जब आप आश्रित आधार वर्गों के सदस्यों तक पहुँचने का प्रयास कर रहे हैं
  • कुछ लोग अपने कोड में सदस्य अभिगम को नेत्रहीन रूप से अस्वीकार करने को प्राथमिकता देते हैं।

7

हालाँकि मैं आमतौर पर इसे पसंद नहीं करता, लेकिन मैंने देखा है कि अन्य लोग इसका उपयोग करते हैं-> बस अंतर्मुखता से सहायता पाने के लिए!


6
  1. जहां एक सदस्य चर स्थानीय चर द्वारा छिपा होगा
  2. यदि आप इसे केवल स्पष्ट रूप से स्पष्ट करना चाहते हैं कि आप एक आवृत्ति विधि / चर कह रहे हैं


कुछ कोडिंग मानक दृष्टिकोण (2) का उपयोग करते हैं क्योंकि वे दावा करते हैं कि यह कोड को पढ़ना आसान बनाता है।

उदाहरण:
मान लें कि MyClass में 'काउंट' नामक एक सदस्य चर है

void MyClass::DoSomeStuff(void)
{
   int count = 0;

   .....
   count++;
   this->count = count;
}

5

एक अन्य मामला है जब ऑपरेटरों को आमंत्रित करना। के बजाय

bool Type::operator!=(const Type& rhs)
{
    return !operator==(rhs);
}

तुम कह सकते हो

bool Type::operator!=(const Type& rhs)
{
    return !(*this == rhs);
}

जो अधिक पठनीय हो सकता है। एक और उदाहरण है कॉपी-एंड-स्वैप:

Type& Type::operator=(const Type& rhs)
{
    Type temp(rhs);
    temp.swap(*this);
}

मुझे नहीं पता कि यह क्यों नहीं लिखा गया है swap(temp)लेकिन यह आम बात है।


अपने अंतिम मामले में, ध्यान दें कि आप एक गैर- constसदस्यीय फ़ंक्शन को अस्थायी ( Type(rhs).swap(*this);कानूनी और सही है) पर कॉल कर सकते हैं, लेकिन एक अस्थायी गैर-कॉन्स्टेंस रेफ़रेंस पैरामीटर (कंपाइलर रिजेक्ट के swap(Type(rhs));साथ-साथ this->swap(Type(rhs));) पर बाँध नहीं सकता है
बेन वोइगट

5

ऐसे कुछ मामले हैं जहां उपयोग this करना आवश्यक है, और कुछ अन्य हैं जहां thisपॉइंटर का उपयोग करना एक समस्या को हल करने का एक तरीका है।

1) उपलब्ध विकल्प : स्थानीय चर और वर्ग के सदस्यों के बीच अस्पष्टता को हल करने के लिए, जैसा कि @ASk द्वारा सचित्र है

2) कोई वैकल्पिक नहीं:this एक सदस्य फ़ंक्शन से एक सूचक या संदर्भ वापस करने के लिए । यह अक्सर किया जाता है (और किया जाना चाहिए) जब अधिक भार operator+, operator-, operator=, आदि:

class Foo
{
  Foo& operator=(const Foo& rhs)
  {
    return * this;
  }
};

ऐसा करना एक मुहावरे को " विधि जंजीर " के रूप में जाना जाता है , जहाँ आप किसी ऑब्जेक्ट पर कोड की एक पंक्ति में कई कार्य करते हैं। जैसे कि:

Student st;
st.SetAge (21).SetGender (male).SetClass ("C++ 101");

कुछ लोग इस सहमति को मानते हैं, अन्य इसे घृणा मानते हैं। मुझे बाद वाले समूह में गिनें।

3) कोई वैकल्पिक नहीं: निर्भर प्रकारों में नामों को हल करने के लिए। यह इस उदाहरण में टेम्प्लेट का उपयोग करते समय आता है:

#include <iostream>


template <typename Val>
class ValHolder
{
private:
  Val mVal;
public:
  ValHolder (const Val& val)
  :
    mVal (val)
  {
  }
  Val& GetVal() { return mVal; }
};

template <typename Val>
class ValProcessor
:
  public ValHolder <Val>
{
public:
  ValProcessor (const Val& val)
  :
    ValHolder <Val> (val)
  {
  }

  Val ComputeValue()
  {
//    int ret = 2 * GetVal();  // ERROR:  No member 'GetVal'
    int ret = 4 * this->GetVal();  // OK -- this tells compiler to examine dependant type (ValHolder)
    return ret;
  }
};

int main()
{
  ValProcessor <int> proc (42);
  const int val = proc.ComputeValue();
  std::cout << val << "\n";
}

4) विकल्प उपलब्ध: कोडिंग शैली के एक भाग के रूप में, दस्तावेज़ों के लिए जो चर चर सदस्य हैं जो स्थानीय चर के विपरीत हैं। मैं एक अलग नामकरण योजना पसंद करता हूं, जहां सदस्य varibales स्थानीय लोगों के समान नाम कभी नहीं रख सकते। वर्तमान में मैं mNameसदस्यों के लिए और nameस्थानीय लोगों के लिए उपयोग कर रहा हूं ।


4

आपको केवल इसका उपयोग करना होगा-> यदि आपके पास दो संभावित नामस्थानों में समान नाम वाला प्रतीक है। उदाहरण के लिए:

class A {
public:
   void setMyVar(int);
   void doStuff();

private:
   int myVar;
}

void A::setMyVar(int myVar)
{
  this->myVar = myVar;  // <- Interesting point in the code
}

void A::doStuff()
{
  int myVar = ::calculateSomething();
  this->myVar = myVar; // <- Interesting point in the code
}

कोड में दिलचस्प बिंदुओं पर, myVar का संदर्भ स्थानीय (पैरामीटर या चर) myVar को संदर्भित करेगा। वर्ग के सदस्य तक पहुँचने के लिए जिसे myVar भी कहा जाता है, आपको "यह->" का स्पष्ट रूप से उपयोग करने की आवश्यकता है।


यह this->बचने के लिए उस तुच्छ का एक उपयोग है (बस स्थानीय चर को एक अलग नाम दें)। के सभी वास्तव में दिलचस्प उपयोग thisभी इस जवाब से उल्लेख नहीं किया गया है।
विस्फ़ोटक -

4

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

निर्मोक

void Foo::bar() {
    misc_nonconst_stuff();
    const Foo* const_this = this;
    const_this->bar(); // calls const version

    dynamic_cast<Bar*>(this)->bar(); // calls specific virtual function in case of multi-inheritance
} 

void Foo::bar() const {}

बाइंडिंग

void Foo::baz() {
     for_each(m_stuff.begin(), m_stuff.end(),  bind(&Foo:framboozle, this, _1));        
     for_each(m_stuff.begin(), m_stuff.end(), [this](StuffUnit& s) { framboozle(s); });         
} 

void Foo::framboozle(StuffUnit& su) {}

std::vector<StuffUnit> m_stuff;

ptr करने वाली सदस्य

void Foo::boz() {
    bez(&Foo::bar);
    bez(&Foo::baz);
} 

void Foo::bez(void (Foo::*func_ptr)()) {
    for (int i=0; i<3; ++i) {
        (this->*func_ptr)();
    }
}

आशा है कि यह इसके अलावा अन्य उपयोगों को दिखाने में मदद करता है-> सदस्य।


3

आपको thisएक पैरामीटर / स्थानीय चर और सदस्य चर के बीच खंडन करने के लिए उपयोग करने की आवश्यकता है ।

class Foo
{
protected:
  int myX;

public:
  Foo(int myX)
  {
    this->myX = myX; 
  }
};

2
नहीं, आपको इसकी आवश्यकता नहीं है, आप इसका उपयोग कर सकते हैं । आप फ़ंक्शन तर्क के लिए एक अलग नाम का भी उपयोग कर सकते हैं, जिसमें एक ही नाम के साथ दो इकाइयां नहीं होने का लाभ है।
विस्फ़ोटक -

3

thisसूचक का मुख्य (या मैं कह सकता हूं, एकमात्र) उद्देश्य यह है कि यह सदस्य फ़ंक्शन को लागू करने के लिए उपयोग की जाने वाली वस्तु को इंगित करता है।

इस उद्देश्य के आधार पर, हमारे पास कुछ मामले हो सकते हैं जो केवल thisसूचक का उपयोग करके समस्या को हल कर सकते हैं।

उदाहरण के लिए, हमें किसी सदस्य फ़ंक्शन में इनवॉइसिंग ऑब्जेक्ट को तर्क के साथ वापस करना होगा एक ही वर्ग ऑब्जेक्ट है:

class human {

... 

human & human::compare(human & h){
    if (condition)
        return h;       // argument object
    else 
        return *this;   // invoking object
    }
};

2

मुझे प्रभावी C ++ पुस्तक में "यह" सूचक के स्पष्ट उपयोग का एक और दिलचस्प मामला मिला।

उदाहरण के लिए, मान लें कि आपके पास एक कास्ट फ़ंक्शन है जैसे

  unsigned String::length() const

आप प्रत्येक कॉल के लिए स्ट्रिंग की लंबाई की गणना नहीं करना चाहते हैं, इसलिए आप इसे कुछ ऐसा करने के लिए कैश करना चाहते हैं

  unsigned String::length() const
  {
    if(!lengthInitialized)
    {
      length = strlen(data);
      lengthInitialized = 1;
    }
  }

लेकिन यह संकलित नहीं करेगा - आप ऑब्जेक्ट को एक कास्ट फ़ंक्शन में बदल रहे हैं।

चाल हल करने के लिए इस कास्टिंग की आवश्यकता है इस -स्थिरांक गैर एक करने के लिए इस :

  String* const nonConstThis = (String* const) this;

फिर, आप ऊपर कर सकेंगे

  nonConstThis->lengthInitialized = 1;

3
या आप lengthउत्परिवर्तित कर सकते हैं , या इसे एक नेस्टेड संरचना में भी रख सकते हैं। कब्ज को दूर करना लगभग एक अच्छा विचार नहीं है।
रिचर्ड जे। रॉस III

3
कृपया नहीं। यदि सदस्य को constसदस्य कार्यों से बदला जाना है, तो यह होना चाहिए mutable। अन्यथा आप जीवन को एक अन्य रखवाले के लिए और अधिक जटिल बना रहे हैं।
डेविड रॉड्रिग्ज - drieas
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.