いつthis->member
クラスのメソッドを明示的に記述する必要がありますか?
いつthis->member
クラスのメソッドを明示的に記述する必要がありますか?
回答:
通常、あなたがする必要はありません、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
}
};
i
かもしれませんが、なぜに存在しないのか理解できませんA
。例を教えてもらえますか?
template<> struct A<float> { float x; };
メソッドでローカル変数を既存のメンバーと同じ名前で宣言する場合、ローカル変数の代わりに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
this
ポインターを明示的に使用する必要がある理由はいくつかあります。
私は通常それが好きではありませんが、他の人がこれを使って->単にインテリセンスからの助けを得るために使うのを見てきました!
もう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));
)
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
地元の人々のために使用しています。
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
この回答では、のすべての非常に興味深い使用法については言及されていません。
他の答えでの(悪い)名前の明確化を無視して、(概要と質問の半分を読んだときに思ったように)これの他の用途は、現在のオブジェクトをキャストする場合、関数オブジェクトにバインドすることですまたは、メンバーへのポインターとともに使用します。
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;
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だけでなく、これの他の使用法を示すのに役立つことを願っています。
this
パラメータ/ローカル変数とメンバー変数を区別するために使用する必要があります。
class Foo
{
protected:
int myX;
public:
Foo(int myX)
{
this->myX = myX;
}
};
this
ポインターの主な(または私が言えるのは、唯一の)目的は、メンバー関数の呼び出しに使用されるオブジェクトを指すことです。
この目的に基づいて、this
ポインターを使用するだけで問題を解決できる場合があります。
たとえば、同じクラスオブジェクトである引数を使用して、呼び出し関数をメンバー関数で返す必要があります。
class human {
...
human & human::compare(human & h){
if (condition)
return h; // argument object
else
return *this; // invoking object
}
};
私は、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;
length
変更可能にしたり、ネストされた構造体に入れたりすることもできます。一定性を捨てることは、ほとんど決して良い考えではありません。
const
メンバーをメンバー関数から変更する場合は、にする必要がありますmutable
。それ以外の場合は、他のメンテナにとって、生活がより複雑になります。