В один из часто задаваемых вопросов Страуструпа, он приводит следующий пример:
template<class Scalar> class complex {
public:
complex() : re(0), im(0) { }
complex(Scalar r) : re(r), im(0) { }
complex(Scalar r, Scalar i) : re(r), im(i) { }
// ...
complex& operator+=(const complex& a)
{ re+=a.re; im+=a.im; return *this; }
// ...
private:
Scalar re, im;
};
и описывает:
Этот тип предназначен для использования в качестве встроенного типа и представление необходимо в объявлении, чтобы сделать возможным создание действительно локальных объектов (т.е. объекты, которые размещены в стеке, а не в куче) и обеспечить правильное встраивание простых операций.
Может ли кто-нибудь помочь объяснить это? Положил re
, im
данные в объявлении класса заставляют объект класса размещаться в стеке? А как насчет встраивания? (Я вижу operator+=
встроенный, он имеет в виду это?)
Помещение данных в определение класса не делает объект
выделить на стеке, но это позволяет. В том месте, где объект
определено, компилятор должен знать его полный размер; если объект
определиться в стеке, компилятор должен знать его размер в
единица перевода, которая определяет это.
Отсутствие данных в определении класса означает, что вы должны принять
некоторые шаги для размещения данных в другом месте, и это в другом месте будет
почти наверняка связаны с динамическим распределением.
Аналогично, встроенная функция может манипулировать только теми данными, которые она видит.
Существуют различные схемы, позволяющие избежать объявлений данных в классе.
Они могут иметь важные преимущества, особенно когда типы данных
сложный и определяемый пользователем. Все они включают динамическое распределение. Какие
Страуструп говорит, что для маленьких, конкретных классов, помещая данные
в классе позволяет им вести себя (и выполнять), как встроенный
типы, без динамического выделения, и часто (из-за встраивания) нет
штраф за абстракцию.
Участники re
а также im
распределяются внутри каждого complex
объект. Это означает, что re
а также im
расположены в стеке если и только если целый complex
Объект есть. Если complex
объект является глобальным, то re
а также im
ни в стеке, ни в куче.
На практике компиляторы будут ставить re
по смещению 0 в объекте и im
по смещению sizeof(Scalar)
, Это означает, что код для operator+=
не нужно много инструкций по сборке, чтобы получить эти элементы. Сами фактические дополнения, вероятно, являются всего лишь двумя инструкциями по сборке, поэтому загрузка 4 элементов и сохранение двух результатов — это основная часть работы. И встраивание работает лучше всего, если есть мало для встраивания.
Это конкретный класс, который не предназначен для получения (потому что в этом нет необходимости).
Вы, вероятно, не хотите определять интерфейс для комплексных чисел, получать различные виды комплексных чисел (какими бы они ни были) и использовать их полиморфно.
Имея все в классе, компилятор, вероятно, может легче оптимизировать это, чем при использовании абстрактного интерфейса и виртуальных функций.
Я не думаю, что здесь есть что-то волшебное, это всего лишь пример того, где уместно использовать класс «тип значения».