Участник:Altazir/Песочница

Материал из Викиверситета

Ортодоксальная каноническая форма класса[править]

Что должно быть:

  • понятие конкретного типа данных
  • понятие ортодоксальной канонической формы
  • пример
  • важность идиомы
  • упражнения

Конкретными типами данных называются типы, определяемые программистом. Их представление определяется на основе примитивных типов Cи, а также других абстрактных или конкретных типов данных, определенных вами. Для конкретных типов можно определять операторы, их имена и поведение. Кроме того, для конкретного типа можно переопределить смысл стандартных операторов Си таких как +,-,/ и *. Таким образом определенный вами тип становится таким же конкретным, как встроенные типы Си int, char, double и т.д. Конкретные типы данных следуют отличать от реализации абстрактных типов данных, так как конкретные типы работают по таким же предсказуемым правилам, что и встроенные типы Си (например int). Они создаются по специальному образцу, в котором члены классов конкретных типов данных передают информацию системе поддержки типов компилятора C++. Это позволяет компилятору генерировать эффективный и надежный код для абстракций произвольной сложности. Назовем эту форму ортодоксальной канонической формой класса. Термин "каноническая" означает, что форма определяет систему правил, которые должны соблюдаться компилятором при генерировании кода, а "ортодоксальная" - что форма непосредственно поддерживается самим языком. Итак, для произвольного класса X ОКФ характеризуется присутствием следующих элементов:

  • конструктора по умолчанию (X::X());
  • копирующего конструктора (X::X(const X&));
  • оператора присваивания (X& operator=(const X&));
  • деструктора (X::~X()).

Для примера рассмотрим абстрактное понятие "точка" для декартовой поверхности. Для полноценной работы с данной абстракцией достаточно определить новый класс с функциями выполняющими доступ к координатам, выполнением операций преобразования, нахождения растояния и т.д. Но если вы хотите, чтобы класс работал как полноценный тип данных, его интерфейс не может ограничиваться только данными операциями. В соответствии с ОКФ его интерфейс должен быть создан по образцу, представленному в листинге ниже:

class Point {
public:
    // открытый интерфейс
    Point operator+(const Point&) const;   // геометрический смысл операций сложения/вычитания неочевиден, большей 
    Point operator-(const Point&) const;   // частью для примера, но можно можно использовать данные операторы в 
                                           // алгоритмах перемещения вектора точек(полигона)
                                           
    double distanceTo(const Point&) const; // растояние до другой точки
    // ...                                // другие интересные операций

    // стереотипые функции
    Point();                        // конструктор по умолчанию
    Point(const Point&);            // конструктор для инициализации новой точки на основе существующей
    Point& operator=(const Point&); // присваивание
    ~Point();                       // деструктор

    // 
    Point(double x, double y);     // инициализация двумя координатами
private:
    double x_, y_;   // координаты точки 
};

Рассмотрим последовательно все функции класса и разберемся как они должны быть реализованы.

Point()

Конструктор, инициализирующие объекты Point значениями по умолчанию при отсутствии контекста инициализации. Для класса Point по умолчанию логичнее всего создавать точку с нулевыми координатами. Реализация конструктора выглядит достаточно прямолинейно:

Point::Point() 
{
    x_ = 0;
    y_ = 0;
}

Конструктор по умолчанию автоматически вызывается компилятором при инициализации элементов вектора объектов. Например, он инициализирует каждый элемент следующего вектора:

Point pntVector[20];   // каждый элемент инициализируется конструктором Point::Point()

Если программист не определил для класса ни одного конструктора, то компилятор сгенерирует конструктор по умолчанию за программиста. Этот конструктор будет вызывать конструкторы по умолчанию для всех членов класса, которые сами по себе являются объектами(в нашем классе Point такие члены отсутствуют). Но учтите: если конструктор по умолчанию генерируется компилятором, то члены класса, не имеющие конструктора по умолчанию, останутся неинициализированными.

Point(const Point&)

Конструктор создает точную копию объекта Point, созданного ранее. В параметре конструктора передается ссылка на Point; в данном случае это означает, что функция получает исходный объект, с которым она работает(вместо указателя на объект или его копии). Реализация довольно проста:

Point::Point(const Point& pnt)
{
    x_ = pnt.x_;
    y_ = pnt.y_;
}