Переопределение различные базовые типы

Переопределение различные базовые типы

Оператор переопределения типов typedef вводит синоним для существующего типа, например

Использование typedef для переопределения типов аналогично директиве #define , но

    #define является директивой препроцессора и обрабатывается перед компиляцией путем простой замены всех вхождений:

typedef широко применяются в Windows API для описания типов функций, применяемых в программировании оконных приложений Windows.

Я пытаюсь использовать идиому PIMPL — скрывая детали реализации класса от пользователя. Я также хочу пойти еще дальше, скрыв фактическое имя класса реализации. Это также должно позволить мне быстро поменять класс реализации, изменив одну строку кода.

Мой подход заключается в следующем:

В заголовочном файле я определяю Public Класс и объявить имя прокси Implementation из того, что было бы классом реализации.

X.h:

В рамках реализации я определяю фактический класс реализации (под другим именем), а затем использую typedef для установки Implementation быть тем классом моего выбора.

x.cpp

К сожалению я получаю ошибку:

в typedef линия. Но в обоих местах (файлы cpp и h) я объявляю класс; один с определением, другой без. Так чего мне не хватает?

Если typedef (или C ++ 11 using ) не может быть использован по причинам, как еще я могу достичь своей цели?

Я видел похожие вопросы об одной и той же ошибке, но обнаружил лишь тривиальные ошибки, такие как:

Решение

Поместите ваш typedef в ваш заголовочный файл и удалите объявление Implementation ,

Вы декларируете Implementation дважды. Однажды в class Implementation; и снова в typedef Private Implementation;

Если вы хотите скрыть Private типа сделать Public шаблонных:

Затем в вашем cpp вы можете объявить это с вашей частной реализацией как:

Еще лучше вы можете скрыть шаблон, используя typedef, как вы изначально планировали:

Другие решения

определите реальный класс реализации (под другим именем), а затем используйте typedef, чтобы установить реализацию для того класса, который я выбрал.

Это проблема. Ты не можешь Имя typedef не является классом. Говоря class Implementation , ты обещаешь Implementation будет определен как фактический класс, а не как имя типа определения.

Избавиться от typedef и переименовать Private в Implementation ,

«Мы говорим Ленин – подразумеваем Партия,

Мы говорим Партия – подразумеваем Ленин».

Одна из целей «эпизодического» ООП – создание необходимых пользователю форм представления (типов данных) в виде классов. Естественное желание, сделать их неотличимыми до такой степени, чтобы с ними можно было работать как с обычными переменными базовых типов. Переопределение операций обеспечивает перепрограммирование операций таким образом, что в качестве операндов в них могут использоваться объекты интересующего нас типа.

Замечание: в Си++ обычно используется термин «переопределение операторов», более того, он закреплен синтаксически. Но коль скоро для обозначения таких действий мы использовали термин «операции» (см. 1.4), то будем до конца последовательны.

Итак, переопределение операций заключается в том, что транслятор «начинает понимать», что означает известная операция, если одним (или всеми) его операндами является объект нужного нам класса. Прежде всего, определимся с правилами такого переопределения, что можно менять, а что нельзя:

· нельзя менять синтаксис языка – количество операндов, приоритеты операций и направление их выполнения;

Читайте также:  Настройка the bat для майл ру

· переопределение операций производится отдельно для каждого сочетания операндов, перестановка операндов транслятором не производится. Например операции c сочетаниями операндов string + char [], char []+ string – это различные операции;

· можно менять способы передачи операндов (по ссылке, по значению), тип и способ возвращения результата;

· никаких ограничений не накладывается на действия, выполняемые над объектами в переопределяемой операции (интерпретация операции может быть любой).

Переопределение операций внутри класса

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

· метод определяется в классе первого операнда;

· первый операнд – текущий объект класса;

· второй операнд – формальный параметр, который может быть передан как по значению, так и по ссылке. Тип формального параметра должен совпадать с типом второго операнда;

· результат операции может быть произвольного типа, он может возвращаться как указатель, ссылка или значение;

· на действия, выполняемые в теле метода, ограничений не накладывается (содержательная интерпретация операции может быть любой);

· если формальный параметр или результат передаются по значению, а объект содержит динамические данные, то в классе необходим конструктор копирования, который автоматически вызывается при передаче такого операнда и возвращении результата по return .

Продолжим усовершенствование класса полинома, введя в него набор арифметических и логических операций с целью сделать его похожим на базовый тип. Параллельно обсудим ряд общих вопросов, касающихся переопределения.

Тип результата операции и способ его формирования может быть любым, а интерпретация – сколь угодно экзотической. Следить нужно только за соблюдением закрытости данных объекта и за корректностью работы с динамическими данными. Например, можно переопределить операцию [] таким образом, что она будет возвращать ссылку на коэффициент полинома, аналогично методу get (см. выше).

// переопределение [] — ссылка на коэффициент

double & operator []( int k )

T.add(*this); // Второй операнд по значению (копия)

return T; // Добавление первого к копии второго

for ( int i =0; i T . n ; i ++) // Второй операнд по значению (копия)

T.pd[i]=-T.pd[i]; // Инвертировать коэффициенты копии второго операнда

T.add(*this); // Копия второго + первый

poly R(n+T.n+1); // Вспомогательный объект — сумма размерностей

for (int i=0;i // Добавление частичных произведений всех пар

return R; // Возврат локального объекта по значению

poly R (* this ); // Копия текущего – первого операнда

В качестве операндов можно использовать не обязательно объекты, но и другие, экзотические формы представления данных этого типа. Например, если коэффициенты полинома хранить в массиве, начиная с первого элемента, а в нулевом хранить размерность полинома, то можно переопределить сложение, создав внутри

poly R((int)*p,p+1); // Создать объект из массива

return *this+R; // p[0]-размерность, p[1]. p[n+1] — коэффициенты

Переопределение операций сравнения имеет стандартную интерпретацию, вызывается внутреннего метода сравнения compare с возвратом логического значения.

Читайте также:  Как разблокировать фейсбук аккаунт

int operator return compare(T)

int operator return compare(T)

int operator==(poly &T)

int operator!=(poly &T)

Особенности переопределения некоторых операций

· разрушение содержимого текущего объекта – левого операнда (аналогично деструктору);

· копирование содержимого объекта-параметра (правого операнда) в текущий объект (аналогично конструктору копирования);

· возвращение ссылки на текущий объект.

poly & operator =( poly & R )< // Присваивание

delete []pd; // Разрушить левую часть (текущий)

load(R.n,R.pd); // Копия правой части (аналог КК)

return *this; > // Возвращает ссылку на левый

delete []pd; // Разрушить левую часть (текущий)

int nn=d[0]; // В начале массива — размерность

load(nn,d+1); // дальше — данные

return *this; > // Возвращает ссылку на левый

При переопределении присваивания в правой части может быть операнд любого типа, необходимо только подобать ему достойную интерпретацию. Например, при присваивании полиному вещественного массива из первого его элемента извлекается размерность, а затем – сами коэффициенты.

// переопределение приведения к int — возвращает размерность

«Преобразовать» объект можно и к указателю. Если указатель интерпретировать как динамический массив, то можно, например, выгрузить в него внутренние данные объекта (например, коэффициенты полинома).

// Переопределение приведения к double* —

// возвращение динамического массива

double *q=new double[n+2];

q [0]= n ; // в нулевой ячейке – размерность полинома

for ( int i =0; i n ; i ++) // начиная с первой — коэфиициенты

Такое преобразование будет срабатывать в том числе и при присваивании объекта-полинома указателю (выражение вида double *q=a1; ) .

// переопределение [] — ссылка на коэффициент

double &operator[](int k)

// переопределение () с двумя параметрами — запись коэффициента

poly &operator()(int k, double v)<

poly T(*this); pd[0]++; return T; >

pd[0]++; poly T(*this); return T; >

static void *operator new(size_t size);

static void operator delete (void *);

// Переопределение операций распределения памяти

public: memory(int sz)

void *malloc(int sz)

void free ( void * q 0) <…>>;

// Класс степенного полинома с собственным распределением памяти

int n; // степень полинома

double *pd; // динамический массив коэффициентов

void load ( int n 0, double p [])<

n=n0; // закрытый метод загрузки массива

double *pd1=(double*) MEM.malloc(sizeof(double)*(n1+1));

pd=pd1; // считать новый за старый

> // память не перераспределяется

n=0; // с нулевым коэффициентом

n=m; // с нулевыми коэффициентами

poly(int n0,double p[]) // конструктор из массива коэффициентов

poly(poly &T) < load(T.n, T.pd); >// конструктор "объект из объекта"

poly ()< MEM . free ( pd ); > // деструктор

// переопределение операторов new и delete в классе

static void *operator new(size_t sz)< return MEM.malloc(sz); >

static void operator delete(void *p)< MEM.free(p); >

poly :: MEM . show (); // Явный вызов метода в статическом элементе

Аналогичные замены нужно сделать и в переопределяемых операциях: присваивании и вводе из потока.

Переопределение операции вне класса

Бывают случаи, когда переопределить операцию внутри класса не удается:

· первый операнд является базовым типом, например, переопределение операции с сочетанием операндов int * poly ;

· первый операнд (текущий объект) требуется передать по значению (а не через указатель) ;

Читайте также:  Как в биосе войти в безопасный режим

· класс первого операнда недоступен, т.е. уже написан и оттранслирован.

Во всех случаях на помощь приходит способ переопределения, в котором принадлежность к классу отсутствует вовсе, а все операнды передаются явно через формальные параметры. Такая функция существует сама про себе, вне класса и имеет следующие особенности:

· первый и второй операнды – формальные параметры, могут быть переданы как по значению, так и по ссылке. Типы формальных параметров должны совпадать с типами операндов;

· если функция-оператор должна иметь доступ к закрытым данным операнда, то она должна быть дружественной в классе этого операнда.

Переопределять операцию вида int * poly приходится, поскольку первый операнд является не классом, а базовым типом. Схема передачи параметров — конвейер значений, второй формальный параметр (второй операнд) – полином – передается по значению, а затем его коэффициенты умножаются на целое. Поскольку на приходится работать с «внутренностями» объекта poly , то этот оператор объявляется дружественным в классе poly (если быть более точным, в нашем примере он одновременно объявляется дружественным в заголовке класса poly и тут же определяется, хотя формально к классу не относится) .

// переопределение операции int*poly — конвейер значений

Обе операции используют схему передачи параметров – конвейер ссылок. Они возвращают в качестве результата ссылку на первый операнд – поток, что позволяет выполнять несколько операций > в цепочке: ссылка на объект – поток будет передаваться по конвейеру.

И наконец, не надо забывать, что при чтении объекта из потока происходит разрушение его старого содержимого. Для этого в нем выполняются действия, аналогичные деструктору, а память при чтении выделяется «по новой».

// переопределение вывода в поток — дружественный оператор

friend ostream &operator

// переопределение ввода из потока — дружественный оператор

friend istream &operator>>(istream &O, poly &T)<

Лабораторный практикум

С использованием синтаксиса переопределения операций разработать стандартную арифметику объектов, включающую арифметические действия над объектами и целыми (вещественными, строками – в зависимости от вида объектов), присваивание, ввод и вывод в стандартные потоки, приведение к базовому типу данных, извлечение и обновление отдельных элементов (например, коэффициентов матрицы или символов строки). По возможности организовать операции в виде конвейера значений, с результатом – новым объектом и сохранением значений входных операндов. Для выбора варианта заданий использовать перечень классов из 10.1.

Вопросы без ответов

Определите содержимое объектов после выполнения методов и переопределенных операций. Опишите схему их взаимодействия (копирование, отображение).

// Общая часть класса для всех вариантов

void load(char *s)

int cmp(string &t)

string &operator=(string &r)

char operator [](int n) < return n>=strlen(str) ? ‘?’ : str[n]; >

string &operator()(char c, int n0, int n1)<

string operator+(string &r)

string operator()(int n0, int n1)<

if (n1 >= strlen(str)) n1=strlen(str)-1;

char c=str[n1+1]; str[n1+1]=’’;

string operator+(string r)

friend string operator+(string one, string &two)

string &operator+(char *s)

string &operator+(string &two)

string operator+(char *s)

string operator+(string two)

string(char c, int n)<

string &operator()(char c, int n0, int n1)<

Ссылка на основную публикацию
Партнерка с оплатой за клики
Уже много раз затрагивалась тема о заработке на партнерках, но сегодня мы поговорим о лучших партнерках с оплатой за клики....
Основные характеристики компьютерной мыши
Компьютерная мышь – периферийное устройство, назначение которого координировать положение графического указателя (курсора) в визуальном интерфейсе операционной системы, а также, обеспечить...
Основы работы в среде windows
Рабочий стол в компьютерной терминологии. Значок и ярлык как графические элементы интерфейса операционной системы. Составные части панели задач Windows. Представление...
Патч камеры для андроид
Snap Camera HDR – отличная камера, сделанная на основе JB 4.2 Camera на Android от разработчика Marginz Software. Записывайте видео...
Adblock detector