"This" işaretçisini ne zaman açıkça kullanmalıyım?


101

Bir this->membersınıfın yöntemini açıkça ne zaman yazmalıyım ?


16
Eminim bu bir aldatmacadır, ama elbette aranamaz. İlk defa değil, keşke bu işaretçiye self denilseydi!

5
Sadece bu değil, keşke bir referans olsaydı.
rlbond

2
Aynı. : | İşte nedeni bu arada: research.att.com/~bs/bs_faq2.html#this
GManNickG

11
Kişi cevabı bilmiyorsa bu yöntem kesinlikle işe yaramaz.
09'a

3
@JohnH .: Hm, research.att.com/~bs/şimdi öyle görünüyor stroustrup.com. Yeni bağlantı: stroustrup.com/bs_faq2.html#this
GManNickG

Yanıtlar:


121

Genellikle buna gerek yoktur this->, ima edilir.

Bazen, sınıf üyelerini ve yerel değişkenleri netleştirmek için kullanılabilecek bir ad belirsizliği vardır. Ancak, burada this->açıkça gerekli olan tamamen farklı bir durum var .

Aşağıdaki kodu göz önünde bulundurun:

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

Atlarsanız this->, derleyici, itüm örneklerinde mevcut olabileceği veya bulunmayabileceği için nasıl davranılacağını bilmez A. iGerçekten de üyesi olduğunu söylemek için A<T>, herhangi biri Tiçin this->ön ek gereklidir.

Not: Aşağıdakileri this->kullanarak öneki atlamak yine de mümkündür :

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
Beyanı kullanmanın güzel kullanımı :)
Faisal Vali

4
Bu özellikle çirkin bir durum. Daha önce ısırılmıştım.
Jason Baker

5
Bu saçma bir soru olabilir ama nedenini anlamıyorum imevcut olmayabilir A. Bir örnek alabilir miyim?
Cam Jackson

1
@CamJackson Kodu görsel stüdyoda denedim. "this->" var olsun ya da olmasın sonuçlar aynıdır. Herhangi bir fikir?
Peng Zhang

8
@CamJackson: Biri tür üzerine sınıfları özelleştirebilir:template<> struct A<float> { float x; };
Macke

31

Bir yöntemde mevcut bir üye ile aynı ada sahip bir yerel değişken bildirirseniz, sınıf üyesine yerel değişken yerine erişmek için this-> var'ı kullanmanız gerekecektir.

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

baskılar:

5
4


1
Cout kullansam iyi olur << A :: a << endl; yerine. "bu" bu durumda önemsizdir.
siddhant3s

3
"M_a" veya "a_" gibi kurallarla isim çatışmasından kaçınmayı tercih ederim.
Tom

19

thisİşaretçiyi açık bir şekilde kullanmanız gerekmesinin birkaç nedeni vardır .

  • Nesnenize bir işleve bir referans iletmek istediğinizde.
  • Üye nesneyle aynı ada sahip yerel olarak bildirilmiş bir nesne olduğunda.
  • Bağımlı temel sınıfların üyelerine erişmeye çalıştığınızda .
  • Bazı kişiler, kodlarındaki üye erişimlerini görsel olarak netleştirmek için gösterimi tercih eder.

7

Genelde hoşuma gitmese de, başkalarının bunu sadece intellisense'den yardım almak için kullandığını gördüm!


6
  1. Bir üye değişkenin yerel bir değişken tarafından gizleneceği yer
  2. Sadece bir örnek yöntem / değişken çağırdığınızı açıkça belirtmek istiyorsanız


Bazı kodlama standartları, kodun okunmasını kolaylaştırdığını iddia ettikleri için yaklaşım (2) kullanır.

Örnek:
MyClass'ın 'count' adında bir üye değişkeni olduğunu varsayın

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

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

6

Kullanmanın kullanılması this gereken birkaç durum vardır ve thisimleci kullanmanın bir sorunu çözmenin bir yolu olduğu başka durumlar da vardır .

1) Mevcut Alternatifler : @ASk ile gösterildiği gibi yerel değişkenler ve sınıf üyeleri arasındaki belirsizliği çözmek için .

2) Alternatif Yok:this Bir üye işlevden bir gösterici veya referans döndürmek için . Bu sık sık yapılır (ve yapılmalıdır) aşırı zaman operator+, operator-, operator=vb:

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

Bunu yapmak, bir kod satırında bir nesne üzerinde birkaç işlem gerçekleştirdiğiniz " yöntem zinciri " olarak bilinen bir deyime izin verir . Gibi:

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

Bazıları bu düşünceyi düşünürken, diğerleri bunu iğrenç bir şey olarak görüyor. Beni ikinci grupta sayın.

3) Alternatif Yok: Bağımlı türlerdeki isimleri çözmek için. Bu, aşağıdaki örnekte olduğu gibi şablonlar kullanılırken ortaya çıkar:

#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) Mevcut Alternatifler: Kodlama stilinin bir parçası olarak, yerel değişkenlerin aksine hangi değişkenlerin üye değişkenler olduğunu belgelemek için. Üye değişkenlerin asla yerellerle aynı ada sahip olamayacağı farklı bir adlandırma şemasını tercih ederim. Şu anda mNameüyeler ve nameyerel halk için kullanıyorum .


5

Diğer bir durum, operatörleri çağırmaktır. Örneğin

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

söyleyebilirsin

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

Hangisi daha okunaklı olabilir. Başka bir örnek de kopyala ve değiştir:

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

Neden yazılmadığını bilmiyorum swap(temp)ama bu yaygın görünüyor.


Son durumda, not dışı bir çağrı anlamına const(geçici üzerinde üye işlev Type(rhs).swap(*this);yasal ve doğrudur) ama geçici kutu (derleyici atılmasına neden olmayan bir const referans parametresine bağlamak değil swap(Type(rhs));de sıra this->swap(Type(rhs));)
Ben Voigt

4

Bunu, yalnızca iki olası ad alanında aynı ada sahip bir sembolünüz varsa kullanmanız gerekir. Örneğin alın:

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
}

Koddaki ilginç noktalarda, myVar'a atıfta bulunmak yerel (parametre veya değişken) myVar'ı ifade edecektir. MyVar olarak da adlandırılan sınıf üyesine erişmek için açıkça "this->" kullanmanız gerekir.


Bu, this->kaçınılması gereken önemsiz bir kullanımdır (sadece yerel değişkene farklı bir ad verin). thisBu yanıtın tüm gerçekten ilginç kullanımlarından bahsedilmiyor bile.
cmaster

4

Bunun diğer kullanımları (özeti okuduğumda ve sorunun yarısını okuduğumda düşündüğüm gibi ...), diğer cevaplarda isim belirsizliğini göz ardı ederek (kötü), mevcut nesneyi dönüştürmek istiyorsanız, onu bir işlev nesnesine bağlamaktır. veya bir üyeye işaretçi ile kullanın.

Oyuncular

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

Bağlayıcı

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-üyeye

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

Umarım bunun sadece bu-> üyeden başka kullanımlarını göstermeye yardımcı olur.


3

thisParametreler / yerel değişkenler ve üye değişkenler arasındaki belirsizliği gidermek için kullanmanız gerekir .

class Foo
{
protected:
  int myX;

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

2
Hayır, ihtiyacın yok, kullanabilirsin . Aynı ada sahip iki öğeye sahip olmama avantajına sahip olan işlev bağımsız değişkeni için farklı bir ad da kullanabilirsiniz.
cmaster -

3

thisİşaretçinin ana (veya diyebilirim, tek) amacı, bir üye işlevi çağırmak için kullanılan nesneyi göstermesidir.

Bu amaçla, sadece thisişaretçi kullanarak sorunu çözebilecek bazı durumlara sahip olabiliriz.

Örneğin, argümanıyla aynı sınıf nesnesiyle üye işlevinde çağırılan nesneyi döndürmemiz gerekir:

class human {

... 

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

2

Etkili C ++ kitabında "bu" işaretçinin açık kullanımıyla ilgili başka ilginç bir durum buldum.

Örneğin, şöyle bir const işleviniz olduğunu varsayalım:

  unsigned String::length() const

Her çağrı için String'in uzunluğunu hesaplamak istemezsiniz, bu nedenle,

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

Ancak bu derlenmez - nesneyi bir const işlevinde değiştiriyorsunuz.

Hüner bu döküm gerektirir çözmek için bu bir karşı const olmayan bu :

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

Sonra, yukarıdakileri yapabileceksiniz

  nonConstThis->lengthInitialized = 1;

3
Ya da lengthdeğişebilir hale getirebilir , hatta iç içe bir yapıya koyabilirsiniz. Sabitliği ortadan kaldırmak neredeyse hiçbir zaman iyi bir fikir değildir.
Richard J. Ross III

3
Lütfen yapma. Üye, constüye işlevlerinden değiştirilecekse, değiştirilmelidir mutable. Aksi takdirde, diğer bakıcılar için hayatı daha karmaşık hale getiriyorsunuz.
David Rodríguez - dribeas
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.