https://online-edu.mirea.ru/course/view.php?id=6362
- class: circle
- class: ArrayParent
- subclass: ArrayChild
-
quantity
иcapacity
, должны быть по разному устроены:quantity
- количество элементов в массивеcapacity
- память для этих элементов в байтах, тогдаcapacity = sizeof(type) * quantity
Ответ: это, конечно, хорошо, но мы вводим
capacity
в количестве элементов, для своего удобства, точнее для нормальной работы функцииnew
(подробнее см. Вопрос 3 и Вопрос 15) -
не понятно как работает
double* ptr;
Ответ: это даст нам указатель на 1 конкретную ячейку. Конечно, сама по себе эта ячейка не массив, но на самом деле после того как выполнится команда
ptr = new double[Dimension]
ячейкаdouble* ptr;
окажется началом нашего массива. Но это не нулевой элемент массива. Вообщем это указатель на начало массива, потом именно по этому указателю будет индексация массива, т.е. array[index] = array[0] + index * sizeof(type) ). -
не понятно как работает
ptr = new double[Dimension]
Ответ: функция
new
последовательно выделяет память типаdouble
(мы сами задаем какого типа будут элементы) для количества элементов равномуcapacity
, именно поэтомуcapacity
у нас отвечает на вопрос: под сколько элементов выделять память, т.е.capacity
лучше измерять в количесве элементов. -
деконструктор, если бы мы не проверяли условие
(ptr != NULL)
, то что тогда удаляла бы функцияdelete
?Ответ: вообще нужно ещё прочитать про ptrnull. А так если
ptr
==ptrnull
, то ничего удалять не нужно, т.к. никакой памяти и так не выделено. -
сравнение
double
Ответ: Арифметика чесел с плавающей точкой. Нельзя сравнивать два числа с плавующей запятой между собой, из за того, что числа с плавующей запятой не могут быть представлены точно, по-этому мы не можем полагаться на оператор сравнения.
Популярная практика сравнения такая:
#include <cmath> #include <limits> bool is_equal(double x, double y) { return std::fabs(x - y) < std::numeric_limits<double>::epsilon(); }
-
может ли быть у конкретного класса абстрактный подкласс? Абстрактный класс единственный во всем дереве классов? Он обязательно должен быть корнем дерева классов?
Ответ: да, в теории может, на практике сложновато выдумать такой пример. Абстрактных классов может быть несколько.
-
зачем в родительском классе объявлять методы без тела? Например:
int tree(vector<int>& graph);
Ответ: если, например, родительский класс абстрактный, то нужно будет эти методы переопределить для каждого производного класса, а потом через указатель на базовый класс вызывать этот метод для каждого из подклассов. Например: родительский абстрактный класс -
Mammal
имеет методSpeech()
, но для каждого из подклассовCow
,Dog
,People
,Lion
этот метод должен быть определен по разному. По всей видимости это еще один способ сделать метод виртуальным. -
должен ли конструктор копий
ArrayMaster(const ArrayMaster& array_existing)
возвращать что-то? А преобразователь типов?Ответ: конструктору копий не нужно ничего возвращать - это же констурктор. Если конструктор копировани отсутстует, то компилятор создает свой собственный конструктор копирования, который выполняет побитовое копирование, но если в классе есть массивы с динимическим выделением памяти, то обязательно нужно писать свой конструктор копирования. Потому что, побитовое копирование создаст указатель, который будет смотреть на тот же объект, что и копируемый указатель, т.е. два указателя смотрят на один и тот же объект. Тогда при измении копии, оригинал тоже будет меняться, чего не должно быть категорически! Преоразователь типов это почти тоже самое, что и конструктор, когда мы вызывает консруктор? -в тот момент, когда создаем объект класса, при создании в этот объект будет передана вся информация, поэтому возвращать что-то в консрукторе не нужно.
Когда используется конструктор копирования:
- передача объекта класса в функцию
- возврат объекта класса из функции
operator=
- при создании компилятором временных объектов
-
что хранит указатель
ptr_
указатели или ссылки?Ответ: я думаю, что ссылки, потому что если бы он хранил указатели, нам пришлось бы их где-то разыменовывать, но мы этого нигде не делаем.
-
double get_element(int index)
илиdouble& get_element(int index)
Ответ: Вариант 1, иначе будет нарушена инкапсуляция.
-
у меня есть два конструктора
ArrayMaster(int Dimension = 100)
иArrayMaster(int quantity = 100, double value = 0)
если я вызову один из них, не указав аргументы, который из них сработает?Ответ: наличие двух конструкторов по умолчанию не допускается.
-
зачем возвращать
*this
в методеArrayMaster& operator=(const vector<double>& vector)
?Ответ: для того, что сработал цепной метод
operator=
, т.е.A = B = C = D
. Если не возвращать*this
, то на первом шагеC = D
ничего не вернется и следующий шаг будет выглядеть так:B = ...
Непонятно, что должно произойти с BКстати выполнение такого цепного метода начнется справа-налево. Как итог будет выполнено следующее:
A = D
По шагам
A = B = C = D
:1. C = D 2. B = C 3. A = B (<=> A = D)
-
что должен возвращать оператор
=
ссылку или самого себя(т.е. свою копию?)Ответ: ссылку на себя; см. Вопрос 12.
-
как работает деструктор производного массива? Он вызывает деструктор родительского? Если это так, тогда зачем его вообще объявлять в производном классе?
Ответ: конструктор при создании производного класса спускается сверху-вниз от родительского к производному, деструктор наоборот поднимается снизу вверх от нашего производного к родительскому. Почему именно так?
Построим аналогию. При создании объекта производного типа создается объект родильского класса, этот объект родительского класса удобно считать за ядро объекта производного типа. Сначало создается ядро, после - оболочка. Сначала разрушается оболочка, потом - ядро.
-
понятно как
capacity_
связано с выделением памяти в конструкторе. Но потом при инкрементированииcapacity_
(задесь ошибка! мы не инкрементируем constcapacity_
) количество выделенной памяти никак не изменяется, что делать? Как тогда происходит выделение новой памяти?Ответ: действительно
capacity_
никак физически не связана с выделенной памятью, это лишь счетчик, чтобы недопустить переполнения. В тот момент, когда счетчик количества элементов массива достигает значенияcapacity_
мы понимаем, что нужно перевыделять память.
-
Лучше выделять линейную память память, это будет быстрее и легче, но будеть проблемой расширить один из массивов(массив массивов, не о матрицах). Если раньше это можно было сделать, перевыделив память под нужный массив, то сейчас нужно как-то извращаться.
-
Как все таки сделать нормальный доступ к элементам через matrix[][]? Там два способа: 1- перегрузка оператора [], теперь он будет возвращать ссылку на строку, которая является массивом, поэтому оператор [] для нее уже определен, там будет номр, но это почему-то плохо(что-то типа двойной досткп к памяти); 2- создание нового подчего-то внутри родительского класса, через который и будет все осуществляться.
-
Когда нужно возвращать ссылку на объект, а когда сам объект?
-
Для чего нужнен виртуальный деструктор?
-
Зачем нужна функция
what()
?Ответ: функция
what()
это метод классаstd::exception
, аналог методаprint()
. -
Зачем нужен виртуальный деструктор?
-
Как сделать красивый вывод матрицы в консоль?
-
Почему если унарный минус возвращает не сам объект, а ссылку на него, то всё ломается.
-
Почему функции ввода\вывода должны быть дружественными?
-
Дружественные функции. Например, как работает сложение через дружественные функции, где первое слагаемое - базоваый класс, второе - мой собсвенный класс?
-
Почему индексация с 1?
Ответ: чтобы корректно работал метод
insert(size_ + 1, data)
. Чтобы добавить в конец нужно вставить элемент на одну позицию больше, чем последний. Если индекс последнего элементаsize_ - 1
, то необходимо вставить его на местоsize_
, но всего элементовsize_
, тогда значит ли это, что последний элемент нужно заменить данным? -
Почему класс
Object
остался внутри классаLinkedList<Type>
.Ответ: для того, чтобы нельзя было вне класса
LinkedList<Type>
или его наследников создать экземпляр классаObject
, это дополнительная защита(см. вопрос 3) -
Почему методы типа
remove()
возвращаютType
, а не экземпляр классаObject
?Ответ: потому что, если бы это было так, то это было бы не безопасно. В экземпляре класса
Object
содержаться указатели на элементы контейнера. Тогда через этот экземпляр можно было бы достать информацию из контейнера. Мы не хотим обращения через удаленный экземпляр к элементам контейнера, потому что этого нам не для чего не нужно.
-
Type value_max = *++(++ptr);
где typeid(*ptr).name() = int. Почему где-то так получается инициализировать указатель типа
int
к типуType
, а где-то нет. -
Как сделать так, чтобы внешний класс, стал дружественным для моего класса?
-
Если объявить класс
IndexOutOfBounds
как чисто виртуальный, то как ловить исключения, которые наследуются от него? -
Как происходит поимка исключений? Как происходит ловля исключений-потомков?