수색…


비고

this 포인터는 이것을 구현하는 데 필요한 라이브러리가없는 C ++ 용 키워드입니다. 그리고 this 포인터라는 것을 잊지 마라! 그래서 당신은 할 수 없습니다 :

 this.someMember();

화살표 기호 -> 사용하여 포인터에서 멤버 함수 또는 멤버 변수에 액세스 할 때 :

this->someMember();

this 포인터에 대한 더 나은 이해를 돕는 다른 유용한 링크 :

'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_goodctd_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 :
    • CtorThisBaseCtorThis 생성자가 입력 될 때까지 완전히 생성됩니다. 따라서 si 를 초기화하는 동안 유효한 상태에 있으므로 액세스 할 수 있습니다.
    • ij(this->i) 에 도달하기 전에 초기화됩니다. 따라서, i 초기화하는 동안 유효 상태에 j , 이에 액세스 할 수있다.
    • jk(j) 에 도달하기 전에 초기화됩니다. 따라서 jk 를 초기화하는 동안 유효한 상태이므로 액세스 할 수 있습니다.
  • 잘못된 생성자에서 ctd_bad :
    • kj(this->k) 에 도달 한 후에 초기화됩니다. 따라서 kj 를 초기화하는 동안 유효하지 않은 상태에 있으며,이 연산자에 액세스하면 정의되지 않은 동작이 발생합니다.
    • CtorThisDerived 하지 때까지 구성되어 CtorThis 구성된다. 따라서, k 를 초기화하는 동안 b 가 유효하지 않은 상태에 있으며이를 액세스하면 정의되지 않은 동작이 발생합니다.
    • 객체 ctd_bad 여전히입니다 CtorThis 가 떠날 때까지 CtorThis() 하고 사용하도록 업데이트되지 않습니다 CtorThisDerived 까지의 VTABLE을 CtorThisDerived() . 따라서 virt_func() 는 호출 할 것인지 또는 CtorThisDerived::virt_func() 를 호출 할 것인지에 관계없이 CtorThis::virt_func() 를 호출합니다.

이 포인터를 사용하여 멤버 데이터에 액세스

이 문맥 this 포인터를 사용하는 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; 

여기에서는 Dog 클래스의 private 변수 이름에 매개 변수 이름을 지정하는 것을 볼 수 있습니다 (this-> name).

위 코드의 출력을 보려면 : http://cpp.sh/75r7

이 포인터 CV- 한정어

this 다른 포인터와 같은 cv-qualified 일 수도 있습니다. 그러나, 때문에 this 매개 변수 목록에 표시되지 않는 매개 변수, 특수 구문이 필요합니다; cv-qualifier는 매개 변수 목록 뒤에 있지만 함수 본문 앞에 나열됩니다.

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에 관계없이 쓸 수 있습니다. 이 때문에 const 는 물리적 인 상태를 수정하더라도 멤버 함수가 객체의 논리적 상태 (객체가 외부 세계에 나타나는 방식)를 변경하지 않음을 나타 내기 위해 사용됩니다 (객체가 보더에서 보이는 방식 ).

논리적 상태는 객체가 관찰자 외부에 나타나는 방식입니다. 그것은 물리적 인 상태에 직접적으로 묶여 있지 않으며 실제로는 물리적 인 상태로 저장되지 않을 수도 있습니다. 외부 관찰자가 변경 사항을 볼 수없는 한, 객체의 모든 비트를 뒤집더라도 논리 상태는 일정합니다.

비트 상태라고도하는 물리적 상태는 객체가 메모리에 저장되는 방식입니다. 이것은 데이터를 구성하는 원시 1과 0의 객체입니다. 객체는 메모리에있는 표현이 결코 변경되지 않으면 물리적으로 상수입니다.

그 C ++ 기지 참고 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_castthis 은 비 CV-자격을 만들기 위해, 당신은 정말, 정말은 안하고 사용해야 mutable 대신. const_cast 실제로 객체에 사용될 때 정의되지 않은 동작을 호출 할 책임이 const 하면서, mutable 안전하게 사용할 수 있도록 설계되었습니다. 그러나 매우 오래된 코드에서이 문제에 부딪 힐 수도 있습니다.

이 규칙의 예외는 const 접근 자의 관점에서 비표준 접근자를 정의하는 것입니다. non-cv-qualified 버전이 호출되면 객체가 const 가 아닌 것으로 보장되므로 UB의 위험이 없습니다.

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

이렇게하면 불필요한 코드 중복을 방지 할 수 있습니다.


경우 일반 포인터와 마찬가지로, thisvolatile (포함 const volatile , 그 대신 캐시되는, 메모리에서 액세스 할 때마다로드됩니다). 다른 포인터를 volatile 으로 선언하는 것과 같은 최적화 효과가 있으므로주의해야합니다.


인스턴스가 cv-qualified 인 경우 액세스 할 수있는 멤버 함수는 this 포인터가 적어도 인스턴스 자체만큼 cv-qualified 인 멤버 함수입니다.

  • 비 cv 인스턴스는 모든 멤버 함수에 액세스 할 수 있습니다.
  • const 인스턴스는 constconst volatile 함수에 액세스 할 수 있습니다.
  • volatile 인스턴스는 volatileconst 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.

이 포인터 참조 한정어

C ++ 11

this cv-qualifier와 마찬가지로 ref-qualifier*this 적용 할 수도 있습니다. ref-qualifier는 normal과 rvalue reference semantics 중 하나를 선택하는데 사용되며, 컴파일러는 어느 것이 더 적절한가에 따라 copy 또는 move 의미를 사용할 수 있으며, 대신에 this *this 적용됩니다.

참조 구문을 사용하는 ref-qualifier에도 불구 this 자체는 여전히 포인터입니다. ref-qualifier는 *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

멤버 함수는 ref-qualifier를 사용하거나 사용하지 않는 오버로드를 가질 수 없습니다. 프로그래머는 둘 중 하나를 선택해야합니다. 고맙게도 cv-qualifier는 ref-qualifier와 함께 사용할 수 있으므로 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&& {}
};


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow