|
ООП С Sharp - Как методы экземпляра и статические методы реализованы в памяти
Как уже упоминалось, каждый объект имеет собственную копию полей экземпляра класса. Однако это не касается методов. Если бы каждый объект имел собственную копию кода метода, это потребовало бы значительного расхода памяти, потому что код методов остается одним и тем же для всех экземпляров объектов. Таким образом, методы экземпляра, как и статические методы, существуют лишь в одном экземпляре и ассоциируются с классом в целом. Позже вы ознакомитесь и с другими типами членов класса (конструкторами, свойствами и так далее), которые содержат код вместо данных и следующих той же логике.
Если методы экземпляра сохраняются только один раз, как же они могут обращаться к корректной копии каждого поля? Другими словами, как компилятор генерирует код, обращающийся к паролю Karli первом вызове метода и к паролю Julian — во втором вызове, как показано в следующем примере:
karli.ChangePassword("OldKarliPassword", "NewKarliPassword");
julian.ChangePassword("OldJulianPassword", "NewJulianPassword");
Ответ состоит в том, что методы экземпляра в действительности принимают дополнительный неявный параметр, представляющий собой ссылку на место в памяти, где хранится соответствующий экземпляр класса. Вы можете думать об этом примере кода, как о дружественной к пользователю версии, которую вам нужно написать, потому что именно так синтаксис C# и работает. Однако вот что в действительности присутствует в скомпилированном коде:
ChangePassword(karli, "OldKarliPassword", "NewKarliPassword");
ChangePassword(julian, "OldJulianPassword", "NewJulianPassword");
Объявление метода static делает вызов чуть более эффективным, поскольку при этом не передается дополнительный параметр. С другой стороны, если метод объявлен как static, но пытается обратиться к любым данным экземпляра, то компилятор выдаст ошибку по той очевидной причине, что вы не можете получить доступ к данным экземпляра, если не имеете адреса экземпляра класса! Это значит, что в примере Authenticator мы не могли объявить ChangePassword() или IsPasswordCorrect() как static, потому что оба эти метода обращаются к полю password, не являющемуся статическим. Интересно то, что хотя скрытый параметр методов экземпляров нигде не объявлен явно, вы можете обращаться к нему в своем коде. Это делается с помощью ключевого слова this. Вы можете переписать код ChangePassword() следующим образом:
public bool ChangePassword(string oldPassword, string newPassword)
{
if (oldPassword == this.password)
{
this.password = newPassword;
return true;
}
else
return false;
}
Обычно вы не должны писать свой код подобным образом, если только вам не нужно различать одинаковые имена переменных. Все, чего вы достигнете здесь — метод станет длиннее и несколько более трудным для чтения.
|