Си++/Объектно-ориентированное программирование: различия между версиями

Содержимое удалено Содержимое добавлено
м <source> -> <syntaxhighlight> (phab:T237267)
 
Строка 10:
Полем класса может быть функция:
 
<big><sourcesyntaxhighlight lang=cpp>
class C
{
Строка 16:
void f();
};
</sourcesyntaxhighlight></big>
 
В этом случае её можно вызывать только для конкретного объекта этого классового типа:
 
<big><sourcesyntaxhighlight lang=cpp>
f(); // вызовется глобальная f
C::f(); // ошибка
Строка 27:
C* ptr;
ptr->f(); // тоже можно
</sourcesyntaxhighlight></big>
 
Такую функцию можно описать прямо внутри класса, это означает то же, что <tt>inline</tt> для глобальных функций:
 
<big><sourcesyntaxhighlight lang=cpp>
class C
{
Строка 40:
}
};
</sourcesyntaxhighlight></big>
 
Но можно её описать (т.е. написать тело) и ниже, например, в .cpp при помещении объявления класса в .h:
 
<big><sourcesyntaxhighlight lang=cpp>
class C
{
Строка 55:
printf("We are %p\n", this);
}
</sourcesyntaxhighlight></big>
 
Такие функции называются «функции-члены» или «методы».
Строка 61:
Так как метод всегда зовется для какого-то объекта, ему всегда передается адрес этого объекта. Этот указатель доступен в теле метода как ключевое слово this. Типа псевдо-переменной this — C* const, если метод описан без слова const в конце, и const C* const — иначе:
 
<big><sourcesyntaxhighlight lang=cpp>
class C
{
Строка 80:
}
 
</sourcesyntaxhighlight></big>
 
Т.е. метод со словом <tt>const</tt> не может изменять свой объект.
Строка 91:
* глобалы.
 
<big><sourcesyntaxhighlight lang=cpp>
class C
{
Строка 104:
}
 
</sourcesyntaxhighlight></big>
 
=== static поля и методы ===
Строка 110:
Вот тут <tt>var</tt> — не поле класса, а просто такая хитрая глобальная переменная:
 
<big><sourcesyntaxhighlight lang=cpp>
class C
{
Строка 116:
static int var;
};
</sourcesyntaxhighlight></big>
 
Её надо обязательно где-то описать, в классе она лишь объявлена:
 
<big><sourcesyntaxhighlight lang=cpp>
int C::var = 1;
</sourcesyntaxhighlight></big>
 
Отличия от глобала:
Строка 130:
Точно так же <tt>statfunc</tt> — не настоящий метод, а просто такая функция:
 
<big><sourcesyntaxhighlight lang=cpp>
class C
{
Строка 136:
static void statfunc();
};
</sourcesyntaxhighlight></big>
 
Описывается она так же, как и метод, но в ней не бывает <tt>this</tt> и она не может прямо использовать имена нестатических (настоящих) полей и методов класса.
Строка 166:
Возможно:
 
<big><sourcesyntaxhighlight lang=cpp>
class B
{
Строка 175:
int fd;
};
</sourcesyntaxhighlight></big>
 
Это означает, что в объекте класса <tt>D</tt> есть все поля класса <tt>B (fb)</tt>, плюс ещё и
Строка 192:
Возможно указать несколько базовых классов (т.н. «множественное наследование»):
 
<big><sourcesyntaxhighlight lang=cpp>
class B
{
Строка 205:
int fd;
};
</sourcesyntaxhighlight></big>
 
Тут в объекте <tt>D</tt> будет подобъекты <tt>B</tt> и <tt>B2</tt>, и три поля: <tt>fb</tt>, <tt>fb2</tt> и <tt>fd</tt>.
Строка 229:
Представим себе:
 
<big><sourcesyntaxhighlight lang=cpp>
class B
{
Строка 246:
pb->f();
 
</sourcesyntaxhighlight></big>
 
то в данном случае решение о том, какую функцию звать — <tt>B::f</tt> или <tt>D::f</tt> — принимается на основе известного компилятору типа указателя, т.е. <tt>B::f</tt>.
Строка 256:
Эта возможность есть, она выглядит так:
 
<big><sourcesyntaxhighlight lang=cpp>
 
class B
Строка 269:
};
 
</sourcesyntaxhighlight></big>
 
В этом случае <tt>pb->f()</tt> будет исполнять совсем иной код. Обычно этот код находит указатель на
Строка 280:
Допустимо ещё и такое:
 
<big><sourcesyntaxhighlight lang=cpp>
 
class B
Строка 288:
};
 
</sourcesyntaxhighlight></big>
 
Это так называемая чисто-виртуальная функция. Объект класса, в котором есть такое, не может быть создан напрямую, только как подобъект в классе-наследнике. Такой класс нельзя использовать в объявлениях объектов, но можно в объявлениях указателей на них и в списках базовых классов других классов.
Строка 298:
=== Полиморфизм и множественное наследование ===
 
<big><sourcesyntaxhighlight lang=cpp>
struct B
{
Строка 334:
// и потом зовет D::b2, и именно адрес этого "переходничка" и кладут в __vtbl
 
</sourcesyntaxhighlight></big>
 
См. ассемблерный код, сгенеренный при использовании библиотеки Microsoft ATL — там такое на каждом шагу.
Строка 346:
Синтаксически [[w:Конструктор (объектно-ориентированное программирование)|конструктор]] есть метод, имя которого совпадает с именем [[w:Класс (программирование)|класса]]:
 
<big><sourcesyntaxhighlight lang=cpp>
class C
{
Строка 356:
}
};
</sourcesyntaxhighlight></big>
 
Создание объекта такого класса обязательно требует указания параметра типа <tt>int</tt>, который помещается в поле <tt>i</tt> объекта.
Строка 373:
Конструкторы локалов зовутся явно по ходу исполнения операторов в блоке.
Синтаксис для глобалов и локалов:
<big><sourcesyntaxhighlight lang=cpp>
MyClass c;
MyClass c1(); // одно и то же, используется конструктор без параметров - УЖЕ НЕТ в новом
Строка 390:
// конструктора из int во временный объект MyClass, который потом копируется
// в c6 - временный объект исключается компилятором
</sourcesyntaxhighlight></big>
 
В С++ есть ключевое слово <tt>explicit</tt>, позволяющее запретить неявное преобразование аргумента конструктора. Применяется только к конструкторам.
<big><sourcesyntaxhighlight lang=cpp>
class MyClass
{
Строка 411:
return 0;
}
</sourcesyntaxhighlight></big>
Вообще, если конструктор имеет 1 параметр, рекомендуется использовать <tt>explicit</tt>, т.к. неявное преобразование типов потенциально опасно.
 
Строка 417:
Создание массива по <tt>new</tt> обязательно использует конструктор без параметров.
Иначе же:
<big><sourcesyntaxhighlight lang=cpp>
MyClass* obj = new MyClass(1, 2);
</sourcesyntaxhighlight></big>
Скобки круглые (квадратные скобки - массив) и идут за именем класса (скобки за словом <tt>new</tt> передают параметры в <tt>operator new</tt>, а не в конструктор).
 
Строка 425:
 
Для таких случаев в синтаксисе конструктора предусмотрен так называемый <tt>ctor</tt>-инициализатор (список инициализации):
<big><sourcesyntaxhighlight lang=cpp>
class B
{
Строка 444:
{
}
</sourcesyntaxhighlight></big>
 
В ctor-инициализаторе может быть проинициализировано любое поле и любая база. При этом для: а) полей, являющимися ссылками; б) для полей классовых типов, не имеющих конструктора без параметров; и в) для базовых классов, не имеющих такого конструктора - элемент в ctor-инициализаторе обязателен.
Строка 460:
Более того, Си++ не делает разницы в синтаксисе для классовых и неклассовых типов, т.е. синтаксис <tt>long(1)</tt> вполне возможен и опять же есть то же самое, что и <tt>(long)1</tt>. Точно так же можно:
 
<big><sourcesyntaxhighlight lang=cpp>
long i = 1;
long i(1); // одно и то же
</sourcesyntaxhighlight></big>
 
Временный объект когда-то будет разрушен, точное время разрушения зависит от реализации, потому надо быть крайне осторожным с указателями на них (поместить такой указатель в контейнер — типичная ошибка начинающего).
Строка 490:
Для такого разрушения используется [[w:деструктор|деструктор]]. Синтаксически это функция с именем <tt>~MyClass</tt>:
 
<big><sourcesyntaxhighlight lang=cpp>
class C
{
Строка 496:
~C();
};
</sourcesyntaxhighlight></big>
 
Деструктор вызывается когда-то для любого объекта.