Рассмотрим начальную точку языка, который имеет только целые числа и поплавки различных размеров, и тип, указывающий на память, который позволяет нам указывать на эти типы.
Корреляция от этого к машинным кодам, используемым ЦП, будет относительно ясной (хотя на самом деле мы могли бы оптимизировать за пределами этого).
Символы, которые мы можем добавить, сохраняя коды в некоторой кодировке, и строки, которые мы создаем как массивы таких символов.
Теперь давайте говорить, что мы хотим, чтобы переместить это в точку, где мы можем иметь что-то вроде:
class User
{
int _id;
char* _username;
public User(int id, char* username)
{
_id = id;
_username = username;
}
public virtaul bool IsDefaultUser()
{
return _id == 0;
}
}
Первое, что нам нужно добавить к нашему языку какая-то структура/класса конструкции, которая содержит члены.Тогда мы можем иметь, насколько:
class User
{
int _id;
char* _username;
}
Наш процесс компиляции знает, что это означает хранение целое, за которым следует указатель на массив символов. Поэтому он знает, что доступ к _id означает доступ к целому числу по адресу начала структуры, а доступ к _username означает доступ к указателю на char при заданном смещении от адреса начала структуры.
Учитывая это, конструктор может существовать как функция, которая делает что-то вроде:
_ctor_User*(int id, char* username)
{
User* toMake = ObtainMemoryForUser();
toMake._id = id;
toMake._username = ObtainMemoryAndCopyString(username);
return toMake;
}
Получение памяти и очистки его при необходимости является сложным, посмотрите на раздел в K & R о том, как использовать указатели на структуры и как malloc ищет один способ, которым это можно было бы сделать.
С этого момента мы можем реализовать IsDefaultUser что-то вроде:
bool _impl_IsDefaultUser(*User this)
{
return this._id == 0
}
Это не может быть переопределен, хотя. Для того, чтобы позволить переопределение мы изменяем Пользователь быть:
class User
{
UserVTable* _vTable;
int _id;
char* _username;
}
Тогда _vTable точек в таблице указателей на функцию, которые в данном случае содержит одну запись, которая является указателем на указанную выше функцию. Тогда вызов виртуального члена становится вопросом поиска правильного смещения в этой таблице и вызова соответствующей функции. У производного класса будет другой _vTable, который будет тем же самым, за исключением того, что для этих методов переопределены разные указатели на функции.
Это замаскировало очень много, а не единственную возможность в каждом случае (например, v-таблицы - это не единственный способ реализовать переопределяемые методы), но показывает, как мы можем построить объектно-ориентированный язык, который может скомпилированы до более примитивных операций над более примитивными типами данных.
Он также замалчивает возможность делать что-то вроде того, как C# скомпилирован в IL, который затем, в свою очередь, скомпилирован в машинный код, так что между языком OO и машинным кодом есть два шага, которые фактически будут исключены ,
"OOPS"? o rly? OOP = объектно-ориентированное программирование, s неверно, так как вряд ли существует множественное число, и даже если это было, это не часть аббревиатуры. Я предпочитаю термин «язык (ы) OO» для того, что вы, возможно, означаете. – delnan
@ delnan: две возможности: OOPS = объектно-ориентированная система программирования. Или он действительно знал больше о Java, чем вы понимаете, и имел в виду назвать это «oops», но заглавными, чтобы подчеркнуть, что это * огромная ошибка, а не только небольшая. :-) –