this->member
클래스의 메서드를 언제 명시 적으로 작성해야 합니까?
research.att.com/~bs/
지금 처럼 보입니다 stroustrup.com
. 새 링크 : stroustrup.com/bs_faq2.html#this
this->member
클래스의 메서드를 언제 명시 적으로 작성해야 합니까?
research.att.com/~bs/
지금 처럼 보입니다 stroustrup.com
. 새 링크 : stroustrup.com/bs_faq2.html#this
답변:
일반적으로 그럴 필요는 없습니다 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
.NET에 존재 하지 않을 수 있는지 이해하지 못합니다 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
포인터를 명시 적으로 사용해야하는 몇 가지 이유가 있습니다 .
또 다른 경우는 연산자를 호출하는 경우입니다. 예 : 대신
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);
있지만 ( 합법적이고 정확함) 임시는 상수가 아닌 참조 매개 변수에 바인딩 할 수 없습니다 (컴파일러도 거부 swap(Type(rhs));
함 this->swap(Type(rhs));
)
using을 this
사용해야하는 경우는 거의 없으며 this
포인터를 사용하는 것이 문제를 해결하는 한 가지 방법 인 경우도 있습니다.
1) 사용 가능한 대안 : @ASk에 설명 된대로 지역 변수와 클래스 멤버 간의 모호성을 해결합니다 .
2) 대안 없음 :this
멤버 함수에서 포인터 또는 참조를 반환 합니다. 이 자주 이루어집니다 (그리고 수행해야합니다) 과부하 때 operator+
, operator-
, operator=
, 등 :
class Foo
{
Foo& operator=(const Foo& rhs)
{
return * this;
}
};
이렇게하면 " 메서드 체이닝 " 이라는 관용구가 허용됩니다. 여기서 한 줄의 코드로 객체에 대해 여러 작업을 수행합니다. 예 :
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
지역 주민 을 위해 사용 하고 있습니다.
두 개의 잠재적 네임 스페이스에 동일한 이름의 기호가있는 경우에만 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->
피해야 할 사소한 용도 중 하나입니다 (지역 변수에 다른 이름을 지정하십시오). 의 모든 흥미로운 용도는 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
매개 변수 / 로컬 변수와 멤버 변수를 명확하게 구분하려면를 사용해야 합니다.
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
각 호출에 대해 String의 길이를 계산하고 싶지 않으므로 다음과 같이 캐시하고 싶습니다.
unsigned String::length() const
{
if(!lengthInitialized)
{
length = strlen(data);
lengthInitialized = 1;
}
}
그러나 이것은 컴파일되지 않습니다-당신은 const 함수에서 객체를 변경하고 있습니다.
이 문제를 해결하려면 이것을 const가 아닌 this 로 캐스팅해야 합니다 .
String* const nonConstThis = (String* const) this;
그런 다음 위에서 할 수 있습니다.
nonConstThis->lengthInitialized = 1;
length
변경 가능 하게 만들 거나 중첩 된 구조체에 넣을 수도 있습니다. constness를 버리는 것은 거의 좋은 생각이 아닙니다.
const
멤버 함수 에서 멤버를 변경 하려면이어야합니다 mutable
. 그렇지 않으면 다른 관리자가 삶을 더 복잡하게 만들고 있습니다.