खोज…
टिप्पणियों
this
पॉइंटर C ++ का एक कीवर्ड है, इसके बाद इसे लागू करने के लिए किसी लाइब्रेरी की जरूरत नहीं है। और this
एक संकेतक है मत भूलना! तो आप ऐसा नहीं कर सकते:
this.someMember();
जैसा कि आप तीर के प्रतीक का उपयोग करके सदस्य कार्यों या सदस्य चर से पहुंचते हैं ->
:
this->someMember();
this
सूचक की बेहतर समझ के लिए अन्य उपयोगी लिंक:
http://www.geeksforgeeks.org/this-pointer-in-c/
https://www.tutorialspoint.com/cplusplus/cpp_this_pointer.htm
इस सूचक
सभी गैर स्थिर सदस्य कार्यों एक छिपा पैरामीटर, वर्ग, नामित का एक उदाहरण के लिए एक सूचक है this
; यह पैरामीटर चुपचाप पैरामीटर सूची की शुरुआत में डाला जाता है, और पूरी तरह से संकलक द्वारा संभाला जाता है। वर्ग के एक सदस्य एक सदस्य समारोह के अंदर पहुँचा है, यह चुपचाप के माध्यम से पहुँचा है this
; यह संकलक को सभी उदाहरणों के लिए एक एकल गैर-स्थैतिक सदस्य फ़ंक्शन का उपयोग करने की अनुमति देता है, और सदस्य फ़ंक्शन को अन्य सदस्य कार्यों को बहुरूपिक रूप से कॉल करने की अनुमति देता है।
struct ThisPointer {
int i;
ThisPointer(int ii);
virtual void func();
int get_i() const;
void set_i(int ii);
};
ThisPointer::ThisPointer(int ii) : i(ii) {}
// Compiler rewrites as:
ThisPointer::ThisPointer(int ii) : this->i(ii) {}
// Constructor is responsible for turning allocated memory into 'this'.
// As the constructor is responsible for creating the object, 'this' will not be "fully"
// valid until the instance is fully constructed.
/* virtual */ void ThisPointer::func() {
if (some_external_condition) {
set_i(182);
} else {
i = 218;
}
}
// Compiler rewrites as:
/* virtual */ void ThisPointer::func(ThisPointer* this) {
if (some_external_condition) {
this->set_i(182);
} else {
this->i = 218;
}
}
int ThisPointer::get_i() const { return i; }
// Compiler rewrites as:
int ThisPointer::get_i(const ThisPointer* this) { return this->i; }
void ThisPointer::set_i(int ii) { i = ii; }
// Compiler rewrites as:
void ThisPointer::set_i(ThisPointer* this, int ii) { this->i = ii; }
एक निर्माता में, this
सुरक्षित रूप से (स्पष्ट या स्पष्ट रूप से) किसी भी क्षेत्र का उपयोग करने के लिए उपयोग किया जा सकता है जो पहले से ही आरंभिक हो चुका है, या माता-पिता वर्ग में किसी भी क्षेत्र; इसके विपरीत, (स्पष्ट रूप से या स्पष्ट रूप से) किसी भी ऐसे क्षेत्र तक पहुँच प्राप्त करना जो अभी तक आरंभीकृत नहीं हुआ है, या किसी व्युत्पन्न वर्ग में कोई भी फ़ील्ड असुरक्षित है, (व्युत्पन्न वर्ग के निर्माण के कारण अभी तक निर्माण नहीं किया गया है, और इस प्रकार इसके क्षेत्र न तो आरम्भिक हैं और न ही मौजूदा हैं)। यह भी आभासी सदस्य कार्यों के माध्यम से कॉल करने के लिए असुरक्षित है this
, निर्माता के रूप में किसी भी व्युत्पन्न वर्ग कार्यों विचार नहीं किया जाएगा (व्युत्पन्न वर्ग अभी तक निर्माण नहीं किया जा रहा है की वजह से, और इस तरह अपनी निर्माता अभी तक vtable अपडेट नहीं हो)।
यह भी ध्यान दें कि एक कंस्ट्रक्टर में, ऑब्जेक्ट का प्रकार वह प्रकार है जो कंस्ट्रक्टर निर्माण करता है। यह सही है भले ही वस्तु को एक व्युत्पन्न प्रकार घोषित किया गया हो। उदाहरण के लिए, उदाहरण के लिए, नीचे ctd_good
और ctd_bad
टाइप कर रहे हैं CtorThisBase
अंदर CtorThisBase()
, और टाइप CtorThis
अंदर CtorThis()
, भले ही उनके विहित प्रकार है CtorThisDerived
। चूंकि बेस क्लास के आसपास अधिक व्युत्पन्न कक्षाएं बनाई जाती हैं, उदाहरण धीरे-धीरे वर्ग पदानुक्रम से गुजरता है जब तक कि यह अपने इच्छित प्रकार का पूरी तरह से निर्मित उदाहरण नहीं है।
class CtorThisBase {
short s;
public:
CtorThisBase() : s(516) {}
};
class CtorThis : public CtorThisBase {
int i, j, k;
public:
// Good constructor.
CtorThis() : i(s + 42), j(this->i), k(j) {}
// Bad constructor.
CtorThis(int ii) : i(ii), j(this->k), k(b ? 51 : -51) {
virt_func();
}
virtual void virt_func() { i += 2; }
};
class CtorThisDerived : public CtorThis {
bool b;
public:
CtorThisDerived() : b(true) {}
CtorThisDerived(int ii) : CtorThis(ii), b(false) {}
void virt_func() override { k += (2 * i); }
};
// ...
CtorThisDerived ctd_good;
CtorThisDerived ctd_bad(3);
इन वर्गों और सदस्य कार्यों के साथ:
- अच्छे निर्माता में,
ctd_good
:-
CtorThisBase
CtorThis
कंस्ट्रक्टर के प्रवेश करने के समय तक पूरी तरह से निर्मित होता है। इसलिए,s
जबकि initialising एक वैध स्थिति में हैi
, और इस प्रकार पहुँचा जा सकता है। -
i
कोj(this->i)
तक पहुंचने से पहले आरंभीकृत किया जाता है। इसलिए,i
j
को इनिशियलाइज़ करते समय एक मान्य स्थिति मेंi
, और इस प्रकार एक्सेस किया जा सकता है। -
k(j)
तक पहुँचने से पहलेj
को इनिशियलाइज़ किया जाता है। इसलिए,j
k
को आरंभीकृत करते समय एक वैध स्थिति में है, और इस प्रकार पहुँचा जा सकता है।
-
- खराब कंस्ट्रक्टर में,
ctd_bad
:-
k
की शुरुआतj(this->k)
तक पहुंचने के बाद की जाती है। इसलिए,k
,j
को इनिशियलाइज़ करते समय अमान्य स्थिति में है और इसे एक्सेस करने के लिए अपरिभाषित व्यवहार का कारण बनता है। -
CtorThisDerived
जब तक के बाद नहीं का निर्माण किया हैCtorThis
का निर्माण किया है। इसलिए,k
को प्रारंभ करते समयb
एक अमान्य स्थिति में है, और इसे एक्सेस करने से अपरिभाषित व्यवहार होता है। - ऑब्जेक्ट
ctd_bad
अभी भीCtorThis
जब तक किCtorThis()
छोड़ नहीं देता, औरCtorThisDerived()
तकCtorThisDerived()
CtorThisDerived
का उपयोग करने के लिए अपडेट नहीं किया जाएगा। इसलिए,virt_func()
CtorThis::virt_func()
virt_func()
को कॉल करेगा, भले ही यह कॉल करने का इरादा हो याCtorThisDerived::virt_func()
।
-
सदस्य डेटा तक पहुँचने के लिए इस सूचक का उपयोग करना
इस संदर्भ में, this
सूचक का उपयोग पूरी तरह से आवश्यक नहीं है, लेकिन यह पाठक को आपके कोड को स्पष्ट कर देगा, यह दर्शाता है कि एक दिया गया फ़ंक्शन या चर वर्ग का सदस्य है। इस स्थिति में एक उदाहरण:
// Example for this pointer
#include <iostream>
#include <string>
using std::cout;
using std::endl;
class Class
{
public:
Class();
~Class();
int getPrivateNumber () const;
private:
int private_number = 42;
};
Class::Class(){}
Class::~Class(){}
int Class::getPrivateNumber() const
{
return this->private_number;
}
int main()
{
Class class_example;
cout << class_example.getPrivateNumber() << endl;
}
इसे यहां कार्रवाई में देखें।
सदस्य डेटा और पैरामीटर के बीच अंतर करने के लिए इस सूचक का उपयोग करना
यह मापदंडों से सदस्य डेटा को अलग करने के लिए एक वास्तविक उपयोगी रणनीति है ... आइए इस उदाहरण को लेते हैं:
// Dog Class Example
#include <iostream>
#include <string>
using std::cout;
using std::endl;
/*
* @class Dog
* @member name
* Dog's name
* @function bark
* Dog Barks!
* @function getName
* To Get Private
* Name Variable
*/
class Dog
{
public:
Dog(std::string name);
~Dog();
void bark() const;
std::string getName() const;
private:
std::string name;
};
Dog::Dog(std::string name)
{
/*
* this->name is the
* name variable from
* the class dog . and
* name is from the
* parameter of the function
*/
this->name = name;
}
Dog::~Dog(){}
void Dog::bark() const
{
cout << "BARK" << endl;
}
std::string Dog::getName() const
{
return this->name;
}
int main()
{
Dog dog("Max");
cout << dog.getName() << endl;
dog.bark();
}
आप यहां देख सकते हैं कि कंस्ट्रक्टर में हम निम्नलिखित कार्य करते हैं:
this->name = name;
यहां, आप देख सकते हैं कि हम पैरामीटर डॉग को क्लास डॉग (यह-> नाम) से प्राइवेट वेरिएबल के नाम पर असेम्बल कर रहे हैं।
उपरोक्त कोड का आउटपुट देखने के लिए: http://cpp.sh/75r7
यह पॉइंटर CV-Qualifiers है
this
भी cv- योग्य हो सकता है, किसी भी अन्य सूचक के समान। हालांकि, this
पैरामीटर को पैरामीटर सूची में सूचीबद्ध नहीं होने के कारण, इसके लिए विशेष सिंटैक्स की आवश्यकता होती है; सीवी-क्वालिफायर को पैरामीटर सूची के बाद सूचीबद्ध किया जाता है, लेकिन फ़ंक्शन के शरीर से पहले।
struct ThisCVQ {
void no_qualifier() {} // "this" is: ThisCVQ*
void c_qualifier() const {} // "this" is: const ThisCVQ*
void v_qualifier() volatile {} // "this" is: volatile ThisCVQ*
void cv_qualifier() const volatile {} // "this" is: const volatile ThisCVQ*
};
जैसा कि this
एक पैरामीटर है, एक फ़ंक्शन को this
cv-qualifier (s) के आधार पर ओवरलोड किया जा सकता है ।
struct CVOverload {
int func() { return 3; }
int func() const { return 33; }
int func() volatile { return 333; }
int func() const volatile { return 3333; }
};
जब this
const
( const volatile
सहित) होता है, तो फ़ंक्शन इसके माध्यम से सदस्य चर लिखने में असमर्थ होता है, चाहे वह स्पष्ट रूप से हो या स्पष्ट रूप से। इसका एकमात्र अपवाद mutable
सदस्य चर है , जिसे कॉन्स्ट-नेस की परवाह किए बिना लिखा जा सकता है। इसके कारण, const
का उपयोग यह इंगित करने के लिए किया जाता है कि सदस्य फ़ंक्शन ऑब्जेक्ट की तार्किक स्थिति को नहीं बदलता है (जिस तरह से ऑब्जेक्ट बाहरी दुनिया को दिखाई देता है), भले ही वह भौतिक स्थिति को संशोधित करता हो (जिस तरह से ऑब्जेक्ट को हुड के नीचे दिखता है )।
लॉजिकल स्टेट वह तरीका है जो ऑब्जेक्ट बाहरी पर्यवेक्षकों को दिखाई देता है। यह सीधे भौतिक अवस्था से जुड़ा नहीं है, और वास्तव में, भौतिक अवस्था के रूप में भी संग्रहीत नहीं किया जा सकता है। जब तक बाहर के पर्यवेक्षक कोई परिवर्तन नहीं देख सकते, तब तक तार्किक स्थिति स्थिर है, भले ही आप ऑब्जेक्ट में हर एक बिट को फ्लिप करें।
भौतिक स्थिति, जिसे बिटवाइज़ स्टेट के रूप में भी जाना जाता है, यह है कि ऑब्जेक्ट को मेमोरी में कैसे संग्रहीत किया जाता है। यह ऑब्जेक्ट का नॉटी-ग्रिट्टी, कच्चा 1s और 0s है जो इसके डेटा को बनाते हैं। एक वस्तु केवल शारीरिक रूप से स्थिर होती है यदि स्मृति में इसका प्रतिनिधित्व कभी नहीं बदलता है।
ध्यान दें कि सी ++ ठिकानों const
तार्किक राज्य, नहीं शारीरिक स्थिति पर सत्ता।
class DoSomethingComplexAndOrExpensive {
mutable ResultType cached_result;
mutable bool state_changed;
ResultType calculate_result();
void modify_somehow(const Param& p);
// ...
public:
DoSomethingComplexAndOrExpensive(Param p) : state_changed(true) {
modify_somehow(p);
}
void change_state(Param p) {
modify_somehow(p);
state_changed = true;
}
// Return some complex and/or expensive-to-calculate result.
// As this has no reason to modify logical state, it is marked as "const".
ResultType get_result() const;
};
ResultType DoSomethingComplexAndOrExpensive::get_result() const {
// cached_result and state_changed can be modified, even with a const "this" pointer.
// Even though the function doesn't modify logical state, it does modify physical state
// by caching the result, so it doesn't need to be recalculated every time the function
// is called. This is indicated by cached_result and state_changed being mutable.
if (state_changed) {
cached_result = calculate_result();
state_changed = false;
}
return cached_result;
}
ध्यान दें कि आप तकनीकी रूप से इस्तेमाल कर सकते हैं, जबकि const_cast
पर this
यह गैर-सीवी-योग्य बनाने के लिए, तुम सच में, वास्तव में नहीं करना चाहिए, और का उपयोग करना चाहिए mutable
बजाय। एक const_cast
अपरिभाषित व्यवहार को लागू करने के लिए उत्तरदायी है जब किसी ऑब्जेक्ट पर उपयोग किया जाता है जो वास्तव में const
, जबकि mutable
का उपयोग करने के लिए सुरक्षित होने के लिए डिज़ाइन किया गया है। हालाँकि, यह संभव है कि आप इसे अत्यंत पुराने कोड में चला सकते हैं।
class CVAccessor {
int arr[5];
public:
const int& get_arr_element(size_t i) const { return arr[i]; }
int& get_arr_element(size_t i) {
return const_cast<int&>(const_cast<const CVAccessor*>(this)->get_arr_element(i));
}
};
यह कोड के अनावश्यक दोहराव को रोकता है।
नियमित संकेत के साथ के रूप में, यदि this
volatile
( const volatile
सहित), तो इसे कैश किए जाने के बजाय इसे एक्सेस किए जाने पर हर बार मेमोरी से लोड किया जाता है। यह ऑप्टिमाइज़ेशन पर उतना ही प्रभाव डालता है जितना कि किसी अन्य पॉइंटर को volatile
करने की घोषणा करना, इसलिए देखभाल की जानी चाहिए।
ध्यान दें कि यदि एक उदाहरण सीवी-योग्य है, केवल सदस्य कार्यों यह उपयोग करने के लिए अनुमति दी है सदस्य कार्यों जिसका हैं this
सूचक कम से कम सीवी योग्य उदाहरण खुद के रूप में है:
- गैर-सीवी उदाहरण किसी भी सदस्य कार्यों का उपयोग कर सकते हैं।
-
const
इंस्टेंसेसconst
औरconst volatile
फंक्शन्स को एक्सेस कर सकता है। -
volatile
उदाहरणvolatile
औरconst volatile
कार्यों का उपयोग कर सकते हैं। -
const volatile
उदाहरणों का उपयोग कर सकतेconst volatile
कार्य करता है।
इस के कुंजी सिद्धांतों में से एक है const
शुद्धता ।
struct CVAccess {
void func() {}
void func_c() const {}
void func_v() volatile {}
void func_cv() const volatile {}
};
CVAccess cva;
cva.func(); // Good.
cva.func_c(); // Good.
cva.func_v(); // Good.
cva.func_cv(); // Good.
const CVAccess c_cva;
c_cva.func(); // Error.
c_cva.func_c(); // Good.
c_cva.func_v(); // Error.
c_cva.func_cv(); // Good.
volatile CVAccess v_cva;
v_cva.func(); // Error.
v_cva.func_c(); // Error.
v_cva.func_v(); // Good.
v_cva.func_cv(); // Good.
const volatile CVAccess cv_cva;
cv_cva.func(); // Error.
cv_cva.func_c(); // Error.
cv_cva.func_v(); // Error.
cv_cva.func_cv(); // Good.
यह पॉइंटर रेफरी-क्वालिफायर
करने के लिए इसी तरह this
सीवी-क्वालिफायर, हम भी करने के लिए रेफरी-क्वालिफायर आवेदन कर सकते हैं *this
। रेफरी-क्वालिफायर सामान्य और rvalue संदर्भ अर्थ विज्ञान के बीच चयन करने के लिए, संकलक या तो कॉपी या स्थानांतरित करें जिस पर अधिक उपयुक्त हैं निर्भर करता है अर्थ विज्ञान उपयोग करने की अनुमति उपयोग किया जाता है, और करने के लिए लागू कर रहे हैं *this
के बजाय this
।
ध्यान दें कि संदर्भ सिंटैक्स का उपयोग करते हुए रेफरी-क्वालीफायर के बावजूद, this
स्वयं अभी भी एक संकेतक है। यह भी ध्यान दें कि रेफ-क्वालिफायर वास्तव में *this
प्रकार को नहीं बदलते हैं; उनका वर्णन करके उनके प्रभावों को समझना और समझना आसान है जैसे उन्होंने किया था।
struct RefQualifiers {
std::string s;
RefQualifiers(const std::string& ss = "The nameless one.") : s(ss) {}
// Normal version.
void func() & { std::cout << "Accessed on normal instance " << s << std::endl; }
// Rvalue version.
void func() && { std::cout << "Accessed on temporary instance " << s << std::endl; }
const std::string& still_a_pointer() & { return this->s; }
const std::string& still_a_pointer() && { this->s = "Bob"; return this->s; }
};
// ...
RefQualifiers rf("Fred");
rf.func(); // Output: Accessed on normal instance Fred
RefQualifiers{}.func(); // Output: Accessed on temporary instance The nameless one
एक सदस्य समारोह में रेफरी-क्वालीफायर के साथ और उसके बिना दोनों अधिभार नहीं हो सकते; प्रोग्रामर को एक या दूसरे के बीच चयन करना होता है। शुक्र है, cv- क्वालीफायर को रेफ-क्वालिफायर के साथ संयोजन के रूप में इस्तेमाल किया जा सकता है, जिससे const
रिलिटी नियमों का पालन किया जा सकता है।
struct RefCV {
void func() & {}
void func() && {}
void func() const& {}
void func() const&& {}
void func() volatile& {}
void func() volatile&& {}
void func() const volatile& {}
void func() const volatile&& {}
};