Преобразования типа: назначение, использование. Правила преобразования типа. Возможные проблемы.



 

Существует два вида преобразований: Явное и неявное.

1.Присвоение "большему типу" значения "меньшего типа". Безопасное присвоение, гарантирует сохранение значения.

unsignedintUnsignedIntVal;

unsigned char UnsignedCharVal;

UnsignedIntVal = UnsignedCharVal;

2.Присвоение "меньшему типу" значения "большего типа". Потенциально опасное присвоение, грозит потерей информации.

intIntVal;

charCharVal;

CharVal = IntVal;

3.Преобразование значения из "меньшего типа" в "больший тип". Называется расширением типа.

(unsignedint)UnsignedCharVal;

4.Преобразование значения из "большего типа" в "меньший тип". Называется сужением типа. Является опасным преобразованием.

(char)IntVal;

Корректное выполнение действий со значениями различных типов в безопасных случаях и в ряде опасных случаев обеспечивается благодаря реализованной в C++ системе преобразования типов.

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

  • Присваивание значения объекту преобразует это значение к типу объекта.

· unsignedintMyIntU;

· MyIntU = 3.14159;

· Эквивалентно

· MyIntU = (unsignedint)3.14159;

  • Передача значения при вызове функции преобразует это значение в тип параметра функции. Он становится известен благодаря прототипу вызываемой функции.

· voidff(int); // Прототип функции.

· :::::

· ff(3.14159);

· Эквивалентно

· ff((int)3.14159);

При этом на стадии трансляции возможно появление предупреждения о сужении типа.

  • В арифметическом выражении тип результата выражения определяется самым "широким" типом среди всех образующих выражение операндов. Этот тип называют результирующим типом выражения. К этому типу преобразуются все остальные операнды.

· unsignedintMyIntU = 5;

· …(MyIntU + 3.14159)…

Результирующим типом выражения здесь оказывается тип double, представленный в выражении литералом 3.14159. В процессе вычисления выражения значение переменной MyIntU преобразуется в 5.0, к которому прибавляется 3.14159.

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

· unsignedintMyIntU = 5;

· MyIntU = MyIntU + 3.14159;

Здесь имеют место два последовательных преобразования:

По ходу вычисления выражения значение переменной MyIntU расширяется до double и к расширенной копии значения 5.0 прибавляется 3.14159. После этого результирующее значение 8.14159, в соответствии с первым правилом, сужается до типа unsignedint. В результате чего получается значение 8, которое и присваивается переменной MyIntU.

  • Указатель на любой не являющийся константой тип можно присваивать указателю типа void*. Этот указатель способен адресовать объекты любого типа данных. Он используется всякий раз, когда неизвестен тип объекта.

· intiVal;

· int *p_iVal = 0;

· char *p_chVal = 0;

· void *p_Val;

· constint *pc_iVal = &iVal;

· p_Val = p_iVal;

· p_Val = p_chVal;

· // ПРАВИЛО 5 выполняется...

· p_Val = pc_iVal;

· //Ошибка: pc_iVal - указатель на константу.

· const void *pcVal = pc_iVal;

· /*

· А здесь всё хорошо! Указателю на константу присвоен указатель на константу.

· */

Перед операцией разыменования указатель типа void* нужно явно преобразовать в указатель на конкретный тип, поскольку в этом случае отсутствует информация о типе, подсказывающая транслятору способ интерпретации битовой последовательности, представляемой указателем:

char *p_chValName = "Marina";

p_Val = p_chValName;

p_chVal = (char*)p_Val; /*Явное приведение.*/

Механизм неявных преобразований может быть отключён посредством явного указания в тексте программы требуемого преобразования типов.

Так, модификация ранее рассмотренного примера

MyIntU = MyIntU + (int)3.14159;

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

 

*Тупо копия. Описать самому… бред.

Тут надо понять все это.

Вопрос равносильный «Что такое beginend?»

 


 

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

 

// Не важно, какой тип будет использовать свободную память, юзается она new не

// зависимоот того класс это, структура или что-то другое.

////////////////

Оператор C++ new позволяет вашим программам распределять память во время выполнения. Для использования оператора new вам необходимо указать количество байтов памяти, которое требуется программе. Предположим, например, что вашей программе необходим 50-байтный массив. Используя оператор new, вы можете заказать эту память, как показано ниже:

 

char *buffer = newchar[50];

 

Говоря кратко, если оператор new успешно выделяет память, он возвращает указатель на начало области этой памяти.

 

Зачем необходимо динамически распределять память с использованием new

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

 

 

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

 

 

class _class

{

private:
chardata;
public:
class(char d):data(d) {} //конструктор (инициализирующий)

};

 

int main

{

    inttt=666;

_class* _example = new _class(tt);//создание в свободной памятиэкземпляра класса

cout<<*_example ->data<<endl; //выведем значение на экран

};

 

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

 

class _class

{

private:
char data;
public:
_class(_class& _example) { //копирующийконструктор

    data = _example.data;

}

};

 

Если вашей программе больше не нужна выделенная память, она должна ее освободить, используя оператор delete. Для освобождения памяти с использованием оператора delete вы просто указываете этому оператору указатель на данную область памяти, как показано ниже:

deletepointer;

 

Деструктор представляет собой функцию, которую C++ автоматически запускает, когда он или ваша программа уничтожает объект. Деструктор имеет такое же имя, как и класс объекта; однако вы предваряете имя деструктора символом тильды (~), например ~_class. В своей программе вы определяете деструктор точно так же, как и любой другой метод класса.

 

class _class

{

private:
char data;
public:
class(char d):data(d) {}

~_class (void){}//указывает деструктор

 

};

 

 

Оператор присваивания

Оператор присваивания обязательно определяется в виде функции класса, потому что он неразрывно связан с объектом, находящимся слева от "=". Определение оператора присваивания в глобальном виде сделало бы возможным переопределение стандартного поведения оператора "=". Пример:

 

class _class

{

private:

intdata;

public:

_class(inti): data(i){}

_class&operator=(const_class& right) { //проверка на самоприсваивание

if (this == &right) {

return *this;

   }

data = right.data;//если не равно само себе, то …

return *this;

}

};


 

Типы отношений между классами. Контейнерные классы: определение, видимость членов класса. Реализация и вызов конструкторов и деструкторов вложенных классов. Реализация и использование методов.

 

//////////////////

//В шпорах написано, что всего два типа

// Спасибо поржал…

///////////////////////

В традиционном ООП предусмотрены три типа отношений между классами:

  • Использование: непосредственная зависимость.
    • член класса А отправляет сообщение объекту класса Б

/////////или

    • член класса А создает или возвращает объекты класса Б.
  • Включение: иногда называется агрегированием. Реализует логические связи типа «является составной частью».
    • объект класса А содержит внутренние объекты класса Б.
  • Наследование: реализует логические связи типа «является частным случаем».
    • ///////////////////// объясняется в 1 билете.

 

Контейнер – это способ организации хранения данных. (стек, массив, связный список….)

Контейнерные классы -- это универсальные шаблонные классы, предназначенные для хранения элементов заданного типа в смежных областях памяти. Стандарт C++ уже включает в себя большое количество контейнеров, как часть STL (StandardTemplateLibrary -- Стандартная Библиотека Шаблонов).

Определяется контейнер, как:

контейнер<тип>объект;

Например:vector<int>example_vector; //создаем вектор целых чисел

Вложенные классы

Один класс может быть объявлен в другом классе, в этом случае внутренний класс называется вложенным:

class_class_1

{ class _class_2

{ · · ·

};

public:

· · ·

};

 

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

 

class cls1 // внешний класс

{ class cls2 // вложенный класс

{ int b; // всекомпоненты private для cls1 и cls2

cls2(int bb) : b(bb){} // конструктор класса cls2

};

public: // public секция для cls1

int a;

class cls3 // вложенный класс

{ int c; // private для cls1 и cls3

public: // public-секция для класса cls3

cls3(int cc): c(cc) {} // конструктор класса cls3

};

cls1(int aa): a(aa) {} // конструктор класса cls

};

void main()

{ cls1aa(1980); // верно

cls1::cls2 bb(456); // ошибка cls2 cannot access private

cls1::cls3 cc(789); // верно

cout<<aa.a<<endl; // верно

cout<<cc.c<<endl; // ошибка 'c' : cannot access private member

          // declared in class 'cls1::cls3'

}

В приведенном тексте программы инструкция cls1::cls2 bb(456) является ошибочной, так как объявление класса cls2 и его компонента находятся в секции private. Для устранения ошибки при описании объекта bb необходимо изменить атрибуты доступа для класса cls2 следующим образом:

public:

Class cls2

{ int b; // private-компонента

public:

cls2(int bb) : b(bb){}

};

Пример доступа к private-компонентам вложенного класса из функций внешнего класса, объявленных со спецификатором friend, приводится ниже.

class cls1 // внешний класс

{ int a;

public:

cls1(intaa): a(aa) {}

class cls2; // неполное объявление класса

void fun(cls1::cls2); // функция получает объект класса cls2

class cls2 // вложенный класс

{ int c;

public:

cls2(int cc) : c(cc) {}

friend void cls1::fun(cls1::cls2); // ф-ция, дружественнаяклассу cls1

intpp(){return c;}

};

};

void cls1::fun(cls1::cls2 dd) {cout<<dd.c<<endl<< a;}

void main()

{ cls1aa(123);

cls1:: cls2 cc(789);

aa.fun(cc);

};

 

Внешний класс cls1 содержит public-функцию fun(cls1::cls2 dd), где dd есть объект, соответствующий классу cls2, вложенному в класс cls1. В свою очередь в классе cls2 имеется friend-функция friend void cls1::fun(cls1::cls2 dd), обеспечивающая доступ функции fun класса cls1 к локальной компоненте с класса cls2.

 


 

Производные классы: простое наследование, основные понятия и определения. Правила определения производного класса, типы наследования, видимость членов класса. Реализация и использование конструкторов и деструкторов базового и производных классов. Использование экземпляров базового и производных классов. Указатели на базовый и производные классы.

 

 

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

Например:

class A{//базовый класс};class B :public A{//public наследование (public -> public, protected -> protected)};class C :protected A{//protected наследование (public, protected -> protected)};class Z :private A{//private наследование (public, protected -> private)};

 

Данные, спрятанные в privateродительского класса, не доступны из производного класса.

 

class A {

private:

       int data;

public:

       A():data(0),vasya(0){}

A(int a, int b):data(a), vasya(b)

virtual~A() {}

       intvasya;

};

 

class B:public A {

private

       intaa;

public:

       B(int a, int b):aa(a), vasya(b)

~B(){}

       func() {

                  int a;

                  a = data; //ошибка доступа(dataбыла в private родительского класса)

                  a = vasya; // все ок(vasyaбыл в public родительского класса)

       };

};

 

int main() {

A* aaa = newA; // создание экземпляра класса А(пустой конструктор)

A* aaa_2 = newA(23,42) // создание экземпляра А с заданными параметрами

B* bbb_2 =newB(23, 52) // создание экземпляра B с заданными параметрами (лучше использовать данный вариант)

A* bbb =newB(23, 52) // создание экземпляра B с заданными параметрами (плохой вариант из-за высвобождения памяти в последствии)

};

 

 


 


Дата добавления: 2018-04-15; просмотров: 368; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!