Quando devo escrever explicitamente this->member
em um método de uma classe?
research.att.com/~bs/
agora stroustrup.com
. Novo link: stroustrup.com/bs_faq2.html#this
Quando devo escrever explicitamente this->member
em um método de uma classe?
research.att.com/~bs/
agora stroustrup.com
. Novo link: stroustrup.com/bs_faq2.html#this
Respostas:
Normalmente, você não precisa, this->
está implícito.
Às vezes, há uma ambigüidade de nome, onde pode ser usado para desambiguar membros de classe e variáveis locais. No entanto, aqui está um caso completamente diferente em que this->
é explicitamente necessário.
Considere o seguinte código:
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();
}
Se omitir this->
, o compilador não saberá como tratar i
, pois pode ou não existir em todas as instanciações de A
. Para dizer que i
é de fato um membro de A<T>
, para qualquer T
, o this->
prefixo é necessário.
Nota: ainda é possível omitir o this->
prefixo usando:
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
que não existe em A
. Posso obter um exemplo?
template<> struct A<float> { float x; };
Se você declarar uma variável local em um método com o mesmo nome de um membro existente, você terá que usar this-> var para acessar o membro da classe em vez da variável local.
#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();
}
estampas:
5
4
Existem vários motivos pelos quais você pode precisar usar o this
ponteiro explicitamente.
Embora eu geralmente não goste, tenho visto outras pessoas usarem isso-> simplesmente para obter ajuda do intellisense!
Alguns padrões de codificação usam a abordagem (2), pois afirmam que torna o código mais fácil de ler.
Exemplo:
suponha que MyClass tenha uma variável de membro chamada 'count'
void MyClass::DoSomeStuff(void)
{
int count = 0;
.....
count++;
this->count = count;
}
Um outro caso é ao invocar operadores. Por exemplo, em vez de
bool Type::operator!=(const Type& rhs)
{
return !operator==(rhs);
}
Você pode dizer
bool Type::operator!=(const Type& rhs)
{
return !(*this == rhs);
}
O que pode ser mais legível. Outro exemplo é o copiar e trocar:
Type& Type::operator=(const Type& rhs)
{
Type temp(rhs);
temp.swap(*this);
}
Não sei por que não está escrito, swap(temp)
mas parece ser comum.
const
função não membro em um temporário ( Type(rhs).swap(*this);
é legal e correto), mas um temporário não pode vincular a um parâmetro de referência não const (o compilador rejeita swap(Type(rhs));
também this->swap(Type(rhs));
)
Existem alguns casos em que o uso this
deve ser usado e há outros em que usar o this
ponteiro é uma maneira de resolver um problema.
1) Alternativas disponíveis : Para resolver a ambigüidade entre as variáveis locais e os membros da classe, conforme ilustrado por @ASk .
2) Sem alternativa: Para retornar um ponteiro ou referência this
de uma função de membro. Isso é feito com freqüência (e deve ser feito) quando a sobrecarga operator+
, operator-
, operator=
, etc:
class Foo
{
Foo& operator=(const Foo& rhs)
{
return * this;
}
};
Isso permite um idioma conhecido como " encadeamento de método ", onde você executa várias operações em um objeto em uma linha de código. Tal como:
Student st;
st.SetAge (21).SetGender (male).SetClass ("C++ 101");
Alguns consideram isso consistente, outros consideram uma abominação. Conte comigo no último grupo.
3) Sem alternativa: para resolver nomes em tipos dependentes. Isso surge ao usar modelos, como neste exemplo:
#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) Alternativas disponíveis: Como parte do estilo de codificação, para documentar quais variáveis são variáveis de membro em oposição a variáveis locais. Eu prefiro um esquema de nomenclatura diferente, onde os membros varibales nunca podem ter o mesmo nome dos locais. Atualmente estou usando mName
para membros ename
locais.
Você só precisa usar this-> se tiver um símbolo com o mesmo nome em dois namespaces potenciais. Considere por exemplo:
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
}
Nos pontos interessantes do código, referir-se a myVar se referirá ao local (parâmetro ou variável) myVar. Para acessar o membro da classe também chamado myVar, você precisa usar explicitamente "this->".
this->
que é trivial evitar (basta dar um nome diferente à variável local). Todos os usos realmente interessantes de this
nem mesmo são mencionados por esta resposta.
Os outros usos para isso (como eu pensei quando li o resumo e metade da pergunta ...), desconsiderando a desambiguação de nomenclatura (ruim) em outras respostas, são se você deseja lançar o objeto atual, vinculá-lo a um objeto de função ou use-o com um ponteiro para membro.
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)();
}
}
Espero que ajude a mostrar outros usos disso além de apenas este-> membro.
Você precisa usar this
para desambiguar entre parâmetros / variáveis locais e variáveis de membro.
class Foo
{
protected:
int myX;
public:
Foo(int myX)
{
this->myX = myX;
}
};
O principal (ou posso dizer, o único) objetivo do this
ponteiro é apontar para o objeto usado para invocar uma função de membro.
Com base neste propósito, podemos ter alguns casos em que apenas o uso de this
ponteiro pode resolver o problema.
Por exemplo, temos que retornar o objeto de chamada em uma função-membro com argumento é um mesmo objeto de classe:
class human {
...
human & human::compare(human & h){
if (condition)
return h; // argument object
else
return *this; // invoking object
}
};
Eu encontrei outro caso interessante de uso explícito do ponteiro "this" no livro Effective C ++.
Por exemplo, digamos que você tenha uma função const como
unsigned String::length() const
Você não quer calcular o comprimento da String para cada chamada, portanto, você deseja armazená-la em cache fazendo algo como
unsigned String::length() const
{
if(!lengthInitialized)
{
length = strlen(data);
lengthInitialized = 1;
}
}
Mas isso não vai compilar - você está mudando o objeto em uma função const.
O truque para resolver isso requer lançando este a um não-const esta :
String* const nonConstThis = (String* const) this;
Então, você será capaz de fazer acima
nonConstThis->lengthInitialized = 1;
length
mutável ou até mesmo colocá-lo em uma estrutura aninhada. Jogar fora a constância quase nunca é uma boa ideia.
const
funções de membro, deve ser mutable
. Caso contrário, você estará tornando a vida mais complicada para você e outros mantenedores.