언제`this` 포인터를 명시 적으로 사용해야합니까?


97

this->member클래스의 메서드를 언제 명시 적으로 작성해야 합니까?


16
나는 이것이 속임수라고 확신하지만 물론 검색 할 수 없습니다. 처음으로이 포인터가 self라고 불 렸으면 좋겠습니다!

5
뿐만 아니라 참고 자료가 되었으면합니다.
rlbond 2009-06-14

2
같은. : | 그런데 그 이유는 다음과 같습니다. research.att.com/~bs/bs_faq2.html#this
GManNickG

11
그 사람이 답을 모르면이 방법은 분명히 작동하지 않습니다.
ASk 09-06-15

3
@JohnH .: 흠, 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
사용 선언의 좋은 사용 :)
Faisal Vali

3
이것은 특히 불쾌한 경우입니다. 나는 전에 물린 적이 있습니다.
Jason Baker

5
이것은 어리석은 질문 일 수 있지만 왜 i.NET에 존재 하지 않을 수 있는지 이해하지 못합니다 A. 예를 들어도 될까요?
Cam Jackson

1
@CamJackson Visual Studio에서 코드를 시도했습니다. 결과는 "this->"의 존재 여부에 관계없이 동일합니다. 어떤 생각?
Peng Zhang

8
@CamJackson : 하나는 유형에 클래스를 전문으로 할 수 있습니다 :template<> struct A<float> { float x; };
Macke

31

기존 멤버와 이름이 같은 메서드에서 로컬 변수를 선언하는 경우 로컬 변수 대신 클래스 멤버에 액세스하려면 this-> var를 사용해야합니다.

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

인쇄물:

5
4


1
나는 cout << A :: a << endl; 대신. ``this "는이 경우 중요하지 않습니다.
siddhant3s 2009-06-15

3
"m_a"또는 "a_"와 같은 규칙과 이름 충돌을 피하고 싶습니다.

19

this포인터를 명시 적으로 사용해야하는 몇 가지 이유가 있습니다 .

  • 객체에 대한 참조를 일부 함수에 전달하려는 경우.
  • 구성원 개체와 이름이 같은 로컬로 선언 된 개체가있는 경우
  • 종속 기본 클래스의 멤버에 액세스하려고 할 때 .
  • 어떤 사람들은 코드에서 멤버 액세스를 시각적으로 명확하게하기 위해 표기법을 선호합니다.

7

나는 보통 그것을 특별히 좋아하지 않지만 다른 사람들이 이것을 단순히 intellisense의 도움을 받기 위해 사용하는 것을 보았습니다!


6
  1. 멤버 변수가 지역 변수에 의해 숨겨지는 곳
  2. 인스턴스 메서드 / 변수를 호출하고 있음을 명시 적으로 명확하게하려면


일부 코딩 표준은 코드를 더 쉽게 읽을 수 있다고 주장하므로 접근 방식 (2)을 사용합니다.

예 :
MyClass에 'count'라는 멤버 변수가 있다고 가정합니다 .

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));)
Ben Voigt

5

using을 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

두 개의 잠재적 네임 스페이스에 동일한 이름의 기호가있는 경우에만 this->를 사용해야합니다. 예를 들어 :

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->피해야 할 사소한 용도 중 하나입니다 (지역 변수에 다른 이름을 지정하십시오). 의 모든 흥미로운 용도는 this이 답변에 언급되지 않았습니다.
cmaster-monica dec. 2014 년

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-to-member

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
아니, 당신은하지 않습니다 필요 당신이 수를 사용 하여. 함수 인수에 대해 다른 이름을 사용할 수도 있습니다.이 경우 이름이 같은 두 항목이 없다는 이점이 있습니다.
cmaster-monica dec. 2014 년

3

this포인터 의 주된 (또는 내가 말할 수있는 유일한) 목적은 멤버 함수를 호출하는 데 사용되는 개체를 가리키는 것입니다.

이를 바탕으로 this포인터 만 사용 하여 문제를 해결할 수있는 경우가있을 수 있습니다.

예를 들어, 인수가 동일한 클래스 객체 인 멤버 함수에서 호출 객체를 반환해야합니다.

class human {

... 

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

2

Effective C ++ 책에서 "this"포인터를 명시 적으로 사용한 또 다른 흥미로운 사례를 발견했습니다.

예를 들어 다음과 같은 const 함수가 있다고 가정합니다.

  unsigned String::length() const

각 호출에 대해 String의 길이를 계산하고 싶지 않으므로 다음과 같이 캐시하고 싶습니다.

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

그러나 이것은 컴파일되지 않습니다-당신은 const 함수에서 객체를 변경하고 있습니다.

이 문제를 해결하려면 이것을 const가 아닌 this 로 캐스팅해야 합니다 .

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

그런 다음 위에서 할 수 있습니다.

  nonConstThis->lengthInitialized = 1;

3
또는 length변경 가능 하게 만들 거나 중첩 된 구조체에 넣을 수도 있습니다. constness를 버리는 것은 거의 좋은 생각이 아닙니다.
Richard J. Ross III

3
하지 마십시오. const멤버 함수 에서 멤버를 변경 하려면이어야합니다 mutable. 그렇지 않으면 다른 관리자가 삶을 더 복잡하게 만들고 있습니다.
David Rodríguez-dribeas 2013
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.