Кристиан, я предложу тебе другой способ.Вы говорите, что знаете C, давайте начнем там.Если вам нужно было реализовать дроби, вы бы использовали struct
, и давайте предположим, что по какой-то причине вы решили динамически распределять свои дроби.У вас есть что-то вроде этого:
typedef struct { int numerator; int denominator; } Fraction;
Fraction *newFraction(int numer, int denom)
{
Fraction *result = (Fraction *)malloc(sizeof(Fraction)); // allocate
result->numerator = numer;
result->denominator = denom;
return result;
}
Fraction *multiplyFraction(Fraction *left, Fraction *right)
{
Fraction *result = (Fraction *)malloc(sizeof(Fraction)); // allocate
result->numerator = left->numerator * right->numerator; // multiple (ignoring reduction)
result->denominator = left->denominator * right->denominator;
return result;
}
И вы будете использовать это как:
Fraction *half = newFraction(1, 2);
Fraction *twothirds = newFraction(2, 3);
Fraction *onethird = multiplyFraction(half, twothirds); // results is 2/6 as we don't reduce in this example
Это ADT - абстрактный тип данных - стиль программирования.Вы объявляете тип данных, содержимое которого является частным («абстрактная» часть) для функций, которые вы предоставляете, и набор функций.
На базовом уровне то, что делает объектно-ориентированное программирование, это просто инвертирование путиты смотришь на это.Вместо «вызова функции multiplyFraction, передающей две дроби», вы говорите «передать сообщение multiplyFraction вместе с дробью в дробь».Используя синтаксис Objective-C, последняя строка выше:
Fraction *onethird = multiplyFraction(half, twothirds);
становится:
Fraction *onethird = [half multiplyFraction:twothirds];
Под капотом этот «метод send» просто становится «вызовом функции» - Objective-C делаетнемного работы, чтобы найти multipleFraction
и затем вызвать его, передав его и half
и twoThirds
.
Почти там!Теперь, чтобы соответствовать измененному синтаксису для вызова, Objective-C также изменяет синтаксис определения multiplyFraction
:
- (Fraction *) multiplyFraction:(Fraction *)right
{
Fraction *result = [Fraction new]; // allocate
result->numerator = ????->numerator * right->numerator;
result->denominator = ????->denominator * right->denominator;
return result;
}
Но что вы пишете для ????
.Поскольку вы увидите, что синтаксис называет только второй параметр (right
), для первого имени нет (который был left
).Objective-C скрывает передачу этого параметра, каждый метод принимает хотя бы один параметр - это «объект» (а не «ADT»), в который отправляется метод.Ему нужно имя, чтобы вы могли ссылаться на него, это имя self
:
- (Fraction *) multiplyFraction:(Fraction *)right
{
Fraction *result = [Fraction new]; // allocate
result->numerator = self->numerator * right->numerator;
result->denominator = self->denominator * right->denominator;
return result;
}
И это по сути это - self
- это имя первого аргумента.
На этой основе строятся объектно-ориентированные языки, например:
- они имели прямой доступ к переменным "instance" - "поля" оригинала
struct
; - они меняютнемного больше синтаксиса - например,
@interface...
заменяет struct...
;и вместо того, чтобы перечислять методы (функции) после типа (struct
) в заголовке, они перечислены внутри его (`@interface); - они обычно добавляют наследование (хотя некоторые языки ADT также имеют это);
- и т. д.
Но под капотом класс Objective-C реализован как C struct
...
HTH