サーチ…


備考

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いずれかの派生クラスの関数が考慮されないように、コンストラクタに(これはまだ構築されていない派生クラスに、したがってそのコンストラクタはまだ仮想テーブルを更新しません)。


また、コンストラクタでは、オブジェクトの型はそのコンストラクタが構築する型です。これは、オブジェクトが派生型として宣言されていても当てはまります。例えば、以下の例では、 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ために:
    • CtorThisBaseは、 CtorThisコンストラクターが入力されるまでに完全に構​​築されます。したがって、 s初期化しつつ、有効な状態であるi 、したがってアクセスすることができます。
    • ij(this->i)に達する前に初期化されます。したがって、 ijを初期化している間は有効な状態にあり、アクセスすることができます。
    • jk(j)に達する前に初期化される。したがって、 jkを初期化している間有効な状態にあり、従ってアクセスすることができる。
  • 不正なコンストラクタでは、 ctd_bad
    • kj(this->k)に達した後に初期化される。したがって、 jを初期化している間、 kは無効な状態にあり、それにアクセスすると未定義の動作が発生します。
    • CtorThisDerivedは、 CtorThisが構築されるまで構築されません。したがって、 bは無効な状態にあり、 kを初期化し、それにアクセスすると未定義の動作が発生します。
    • オブジェクトctd_badまだあるCtorThisそれが去るまでCtorThis()および使用するように更新されることはありませんCtorThisDerivedまでのvtableのをCtorThisDerived()したがって、 virt_func()はそれを呼び出すか、 CtorThisDerived::virt_func()を呼び出すかにかかわらず、 CtorThis::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; 

ここでは、クラスDog(this-> name)のプライベート変数の名前にパラメータ名を代入していることがわかります。

上記のコードの出力を確認するには: http : //cpp.sh/75r7

このポインタCV-修飾子

thisは他のポインタと同じcv修飾されたものでもあります。ただし、 thisパラメータがパラメータリストにリストされていないため、 thisために特別な構文が必要です。 cv修飾子は、パラメータリストの後、関数の本体の前にリストされます。

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に基づいて関数をオーバーロードすることができます

struct CVOverload {
    int func()                { return    3; }
    int func() const          { return   33; }
    int func() volatile       { return  333; }
    int func() const volatile { return 3333; }
};

thisconstconst volatileを含む)の場合、暗黙的または明示的に関わらず、関数はメンバー変数に書き込むことができません。唯一の例外はmutableメンバ変数であり、定数にかかわらず記述できます。このため、 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;
}

技術的に thisconst_cast - const_castで使用することができますが、 本当に本当に本当に本当に本当のはずですが、代わりにmutableを使うべきです。 const_castは、実際 constであるオブジェクトに対して使用されるときは未定義の動作を呼び出すのに対し、 mutableは安全に使用するように設計されています。しかし、非常に古いコードでこれを実行する可能性があります。

この規則の例外は、 constアクセサーの観点から非cv修飾アクセサーを定義することです。 cv修飾されていないバージョンが呼び出された場合、オブジェクトが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));
    }
};

これにより、不要なコードの重複が防止されます。


通常のポインタと同様に、 thisvolatileconst volatileを含む)の場合、キャッシュされずにアクセスされるたびにメモリからロードされます。これは、他のポインタがvolatileと宣言するのと同じように最適化に影響しますので、注意が必要です。


インスタンスがcv修飾されている場合、アクセスが許可されるメンバ関数は、 thisポインタが少なくともインスタンス自体のcv修飾されたメンバ関数だけであることに注意してください。

  • 非cvインスタンスは、任意のメンバ関数にアクセスできます。
  • constインスタンスは、 constおよびconst volatile関数にアクセスできます。
  • volatileインスタンスはvolatileおよびconst volatile関数にアクセスできます。
  • const volatileインスタンスはconst volatile関数にアクセスできます。

これはconst正確さの重要な教義の1つです。

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修飾子と同様に、 ref修飾子*thisも適用できます。 REF-修飾子はコンパイラがコピーのいずれかを使用するか、より適切であるかに応じてセマンティクスを移動できるように、通常と右辺値参照セマンティクスの間で選択するために使用され、そしてするために適用される*this代わりにthis

参照構文を使用するref-qualifierにもかかわらず、 this自体は依然としてポインタであることに注意してください。また、ref修飾子は*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修飾子はref修飾子と組み合わせて使用​​することができ、 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