web-dev-qa-db-ja.com

「this」ポインタをいつ明示的に使用する必要がありますか?

いつ明示的にthis->memberクラスのメソッドで?

85
user53670

通常、必要はありません、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
    }

};
106
ASk

既存のメンバーと同じ名前のメソッドでローカル変数を宣言する場合、ローカル変数の代わりに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

30
PaV

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

  • オブジェクトへの参照を何らかの関数に渡したい場合。
  • メンバーオブジェクトと同じ名前のローカルに宣言されたオブジェクトがある場合。
  • 依存ベースクラス のメンバーにアクセスしようとしているとき。
  • 一部の人々は、コード内のメンバーアクセスを視覚的に明確にする表記法を好んでいます。
17
avakar
  1. メンバー変数がローカル変数によって隠される場所
  2. インスタンスメソッド/変数を呼び出していることを明示的に明確にしたい場合


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

例:
MyClassには「count」というメンバー変数があるとします

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

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

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

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

あなたは言うことができます

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

より読みやすいかもしれません。もう1つの例は、コピーアンドスワップです。

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

なぜswap(temp)と書かれていないのかわかりませんが、これはよくあるようです。

5
rlbond

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

1)Alternatives Available:ローカル変数とクラスメンバーのあいまいさを解決するには、 @ ASkで示されているように

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

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

これを行うと、「 method chaining 」というイディオムが許可され、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)利用可能な代替:コーディングスタイルの一部として、どの変数がローカル変数ではなくメンバー変数であるかを文書化する。メンバーvaribalesがローカルと同じ名前を持つことは決してできない、別の命名スキームを好みます。現在、メンバーにはmNameを、ローカルにはnameを使用しています。

5
John Dibling

私はたいていそれを好みませんが、他の人がこれを使用するのを見たことがあります->単にインテリセンスから助けを得るために!

5
Brad Robinson

2つの名前空間に同じ名前のシンボルがある場合にのみ、これを使用する必要があります。例:

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->」を使用する必要があります。

4
Joe Schneider

他の答えの(悪い)命名の曖昧さを無視して、これの別の用途(要約と質問の半分を読んだときに思ったように...)は、現在のオブジェクトをキャストし、関数オブジェクトにバインドする場合ですまたは、メンバーへのポインターで使用します。

キャスト

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以外のこの使用法を示すのに役立つことを願っています。

4
Macke

一部の人々は、thisがどのように参照されるべきかについて話していましたが、私はこれ以上同意できませんでした。プリプロセッサコードのlyい行でそれをシミュレートできると言いたいだけです。

#define self (*this)

これは使用しないでください:-)

4
Enn Michael

thisを使用して、パラメーター/ローカル変数とメンバー変数を明確にする必要があります。

class Foo
{
protected:
  int myX;

public:
  Foo(int myX)
  {
    this->myX = myX; 
  }
};
3
Brian R. Bondy

thisポインターの主な(または私が言える唯一の)目的は、メンバー関数を呼び出すために使用されるオブジェクトを指すことです。

この目的に基づいて、thisポインターを使用するだけで問題を解決できる場合があります。

たとえば、引数が同じクラスオブジェクトであるメンバー関数で呼び出しオブジェクトを返す必要があります。

class human {

... 

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

Effective C++ブックで、「this」ポインターを明示的に使用する別の興味深い事例を見つけました。

たとえば、次のようなconst関数があるとします

  unsigned String::length() const

各呼び出しについて文字列の長さを計算したくないので、次のようなことをしてそれをキャッシュしたいです

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

しかし、これはコンパイルされません-const関数でオブジェクトを変更しています。

これを解決するためには、thisを非const thisにキャストする必要があります。

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

その後、上記でできるようになります

  nonConstThis->lengthInitialized = 1;
2
Ariel