Как указатель «this» указывает на разные объекты? - PullRequest
1 голос
/ 13 апреля 2011

Предположим, у меня есть класс:

class test {
public:
   void print();
private:
   int x;
};

void test::print()  
{  
    cout<< this->x;  
}

и у меня есть следующие определения переменных:

test object1;
test object2;

Когда я звоню object1.print() this, случается, что хранится адрес object1, и поэтому я получаю x из object1 напечатанного, а когда я звоню object2.print() this, случается, чтобы хранить адрес object2 и я получаю x из object2 напечатано. Как это происходит?

Ответы [ 5 ]

6 голосов
/ 13 апреля 2011

Каждая нестатическая функция-член имеет скрытый скрытый параметр «текущий объект», который предоставляется вам как указатель this.

Так что вы можете думать, что для

test::print();

есть некоторые

test_print( test* this );

глобальная функция и так, когда вы пишете

objectX.print();

в вашем коде компилятор вставляет вызов

test_print(&objectX);

и таким образом функция-член знает адрес «текущего» объекта.

2 голосов
/ 13 апреля 2011

Вы можете думать, что указатель this является неявным аргументом для функций.Представьте себе небольшой класс, такой как

class C {
public:
  C( int x ) : m_x( x ) { }

  void increment( int value ) {
    m_x += value; // same as 'this->m_x += value'
  }

  int multiply( int times ) const {
    return m_x * times; // same as 'return this->m_x * times;'
  }

private:
  int m_x;
};

, который позволяет вам писать код, подобный

C two( 2 );
two.increment( 2 );
int result = two.multiply( 3 );

Теперь, в действительности, происходит то, что функции-члены increment и multiply вызываютсядополнительный аргумент-указатель, указывающий на объект, для которого вызывается функция.Этот указатель известен как this внутри метода.Тип указателя this отличается в зависимости от того, является ли метод const (как multiply) или нет (как в случае с increment).

Вы можете сделать что-токак и вам самим, подумайте:

class C {
public:
  C( int x ) : m_x( x ) { }

  void increment( C * const that, int value ) {
    that->m_x += value;
  }

  int multiply( C const * const that, int times ) const {
    return that->m_x * times;
  }

private:
  int m_x;
};

вы можете написать код, подобный

C two( 2 );
two.increment( &two, 2 );
int result = two.multiply( &two, 3 );

Обратите внимание, что тип указателя this равен C const * const для multiplyфункция, поэтому как сам указатель const, так и объект, на который указывает!Вот почему вы не можете изменять переменные-члены внутри метода const - указатель this имеет тип, который запрещает это.Это может быть решено с помощью ключевого слова mutable (я не хочу, чтобы зацикливаться слишком далеко, поэтому я не буду объяснять, как это работает), но даже с использованием const_cast:

int C::multiply( int times ) const {
  C * const that = const_cast<C * const>( this );
  that->m_x = 0; // evil! Can modify member variable because const'ness was casted away
  // ..
}

Я упоминаю об этом, поскольку он демонстрирует, что this не такой особенный указатель, как может показаться, и этот конкретный взлом часто является лучшим решением, чем создание переменной-члена mutable, поскольку этот взлом является локальным для одногофункция, тогда как mutable делает переменную mutable для всех const методов класса.

1 голос
/ 13 апреля 2011

this имеет разные значения для разных объектов

1 голос
/ 13 апреля 2011

Каждый экземпляр теста класса получает свою собственную копию переменной-члена x.Поскольку x уникален для каждого экземпляра, значением может быть все, что вы хотите.Переменная this ссылается на экземпляр, с которым она связана.Вам не нужно использовать переменную this.Вы можете просто написать:

void test::print()
{
   cout << x;
}
1 голос
/ 13 апреля 2011

Можно подумать, что this - это просто указатель на память для любого объекта, с которым вы сейчас работаете. Так что если вы делаете obj1.print(), то this = &obj1;. Если вы делаете obj2.print(), то this = &obj2;.

...