`this`ポインタを明示的に使用する必要があるのはいつですか?


97

いつthis->memberクラスのメソッドを明示的に記述する必要がありますか?


16
これは間違いだと思いますが、もちろん検索できません。初めてではありませんが、このポインタがselfと呼ばれたことを願っています!

5
それだけでなく、参考にしてほしい。
rlbond 2009年

2
同じ。:| ここでは道で、なぜです:research.att.com/~bs/bs_faq2.html#this
GManNickG

11
人が答えを知らない場合、この方法は明らかに機能しません。
ASk

3
@JohnH .:うーん、research.att.com/~bs/今のように見えますstroustrup.com。新しいリンク:stroustrup.com/bs_faq2.html#this
GManNickG 2016

回答:


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かもしれませんが、なぜに存在しないのか理解できませんA。例を教えてもらえますか?
カムジャクソン

1
@CamJacksonビジュアルスタジオでコードを試しました。「this->」が存在してもしなくても、結果は同じです。何か案が?
Peng Zhang

8
@CamJackson:一つは、タイプにクラスを特化することができますtemplate<> struct A<float> { float x; };
マッケ

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;を使用する方が良いでしょう。代わりに。``これは、」ここでは重要ではない。
siddhant3s

3
「m_a」や「a_」のような規則との名前の衝突を避けたいだけです。
トム

19

thisポインターを明示的に使用する必要がある理由はいくつかあります。

  • オブジェクトへの参照を関数に渡したい場合。
  • メンバーオブジェクトと同じ名前のローカルに宣言されたオブジェクトがある場合。
  • 依存する基本クラスのメンバーにアクセスしようとしているとき。
  • 一部の人々は、コードでメンバーのアクセスを視覚的に明確にする表記法を好みます。

7

私は通常それが好きではありませんが、他の人がこれを使って->単にインテリセンスからの助けを得るために使うのを見てきました!


6
  1. メンバー変数がローカル変数によって隠される場所
  2. インスタンスメソッド/変数を呼び出していることを明示的に明らかにしたいだけの場合


一部のコーディング標準では、コードを読みやすくするためのアプローチ(2)を使用しています。

例:
MyClassに 'count'というメンバー変数があると仮定します

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

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

5

もう1つのケースは、オペレーターを呼び出す場合です。例えばの代わりに

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);合法で正しい)、テンポラリは非const参照パラメーターにバインドできないことに注意してください(コンパイラーswap(Type(rhs));も同様に拒否しますthis->swap(Type(rhs));
Ben Voigt

5

usingを使用するthis 必要がある場合はほとんどありませんが、thisポインタを使用することが問題を解決する1つの方法である場合もあります。

1)利用可能な代替案@ASkで示されているように、ローカル変数とクラスメンバー間のあいまいさを解決します

2)代替なし:thisメンバー関数からのポインターまたは参照を返す。これが頻繁に行われている(そして実行する必要があります)のオーバーロードするときoperator+operator-operator=、など:

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

これを行うと、「メソッドチェーン」と呼ばれるイディオムが許可されます。この方法では、1行のコードでオブジェクトに対して複数の操作を実行します。といった:

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)利用可能な代替案:コーディングスタイルの一部として、ローカル変数ではなく、どの変数がメンバー変数であるかを文書化します。メンバーの変数がローカルと同じ名前になることは決してないような、異なる命名方式を好みます。現在、私はmNameメンバーとname地元の人々のために使用しています。


4

2つの潜在的な名前空間に同じ名前のシンボルがある場合にのみ、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->回避するのが簡単な1つの使用法です(ローカル変数に別の名前を付けるだけです)。thisこの回答では、のすべての非常に興味深い使用法については言及されていません。
cmaster-モニカを14

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

this-> memberだけでなく、これの他の使用法を示すのに役立つことを願っています。


3

thisパラメータ/ローカル変数とメンバー変数を区別するために使用する必要があります。

class Foo
{
protected:
  int myX;

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

2
いいえ、あなたはしていない必要があるあなたがすることができ、それを使用し、それを。関数の引数に別の名前を使用することもできます。これには、同じ名前の2つのエンティティがないという利点があります。
cmaster-モニカ

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

呼び出しごとに文字列の長さを計算したくないので、次のようにキャッシュします

  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変更可能にしたり、ネストされた構造体に入れたりすることもできます。一定性を捨てることは、ほとんど決して良い考えではありません。
リチャードJ.ロスIII

3
しないでください。constメンバーをメンバー関数から変更する場合は、にする必要がありますmutable。それ以外の場合は、他のメンテナにとって、生活がより複雑になります。
デビッド・ロドリゲス-2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.