Шпаргалка по "Программированию"

Автор: Пользователь скрыл имя, 08 Ноября 2011 в 12:07, шпаргалка

Краткое описание

Работа содержит ответы на вопросы по дисциплине "Программирование".

Файлы: 1 файл

default.doc

— 264.50 Кб (Скачать)

Базовый  класс  иерархии  типа  обычно  содержит  ряд  виртуальных  функ-

ций,  обеспечивающих  динамическую  типизацию.  Часто  в  базовом  классе  эти виртуальные  функции фиктивны и имеют пустое тело. Эти функции существуют как некоторая абстракция, конкретная реализация им придается в производных  классах.  Такие  функции,  тело  которых  не  определено,  называются  чисто виртуальными функциями. Общая форма записи чисто виртуальной функции имеет вид virtual  прототип функции = 0; 

Чисто  виртуальная  функция  используется  для  того,  чтобы  отложить  ре-

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

классов. Если base – абстрактный класс, то для инструкций base a;

base *p= new base;

компилятор выдаст сообщение об ошибке. В то же время  вполне можно использовать инструкции вида rect b;

base *p=&b;

base &p=b;

Чисто виртуальную  функцию, как и просто виртуальную  функцию, необя-

зательно переопределять в производных классах. При этом если в производном классе она  не переопределена, то этот класс тоже будет абстрактным, и при попытке  создать объект этого класса компилятор выдаст ошибку. Таким образом, забыть переопределить чисто виртуальную функцию невозможно. Абстрактный базовый класс навязывает определенный интерфейс всем производным от него классам. Главное назначение абстрактных классов – в определении интерфейса для некоторой иерархии классов. Класс можно сделать абстрактным, даже если все его функции определены.  Это  можно  сделать,  например,  чтобы  быть  уверенным,  что  объект  этого класса создан не будет. Обычно для этих целей выбирается деструктор.

class base

{   компоненты-данные 

     public:

         virtual ~base() = 0;

         компоненты-функции 

}

base ::~base()

{реализация  деструктора} 

Объект класса base создать невозможно, в то же время  деструктор его оп-

ределен и будет  вызван при разрушении объектов производных  классов.

Для иерархии типа полезно иметь базовый абстрактный класс. Он содер-

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

 
 
 
 
 
 
 
 

38.Proxi-классы.

  Реализация  скрытия данных и интерфейса некоторого класса может быть

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

-  реализация  исходного класса, компоненты которого  требуется скрыть;

-  реализация proxi-класса для доступа к компонентам  исходного класса;

-  функция,  в которой вызываются компоненты proxi-класса 

// заголовочный  файл cls.h для класса cls

class cls

{  int val;

public:

    cls(int);

    set(int);

    int get() const;

};

  // файл реализации  для класса cls

#include "cls.h"

cls :: cls(int v) {val=v;} 

cls :: set(int v) {val=v;}

int cls :: get() const {return val;}

  // заголовочный файл prox.h для proxi-класса prox

class cls;           // предварительное объявление класса cls

class prox

{   cls *pr;          // для этого и требуется предварительное  объявление 

 public:

     prox(int);

     set(int);

     int get() const;

     ~prox();

};

  // файл реализации для proxi-класса prox

#include "prox.h"

#include "cls.h"

prox :: prox(int vv) {pr=new cls(vv);}

prox :: set(int vv){pr->set(vv);}

int prox :: get() const {return pr->get();}

prox :: ~prox(){delete pr;}

  // программа скрытия данных класса cls посредством proxi-класса prox

#include <iostream>

using namespace std;

#include "prox.h"

int main()

{ prox obj(1);

  cout<<”  Значение val класса cls = ”<<obj.get()<<endl;

  obj.set(2);

  cout<<”  Значение val класса cls = ”<<obj.get()<<endl;

}

В результате выполнения программы получим:

Значение val класса cls = 1

Значение val класса cls = 2

В main()-функцию  включается только файл реализации  prox.cpp, при этом

отсутствует  указание  на  существование  класса  cls.  Следовательно,  private-данные класса cls скрыты от клиента.

 
 
 

39.40.Пространство имен. Пространство имен как объявление. Пространство имен как директива.

Пространства  имен .

При  совпадении имен разных элементов в одной  области действия часто 

возникает  конфликт  имен.  Наиболее  часто  это  возникает  при  использовании 

различных  пакетов  библиотек,  содержащих,  например,  одноименные  классы.

Пространства  имен  используются  для  разделения  глобального  пространства

имен, что позволяет уменьшить количество конфликтов.

 

Ключевое  слово using как директива.

Инструкция  using  namespace  имя    позволяет  предоставить  все  имена,

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

#include <iostream>

using namespace std;

namespace NAME

{ int n1=1;

   int n2=2;

}

// int n1;    приводит к неоднозначности в main  для переменной  n1

int main()

{  NAME::n1=3;

   // n1=3;            // error   'n1' : undeclared identifier 

   // n2=4;            // error   'n2' : undeclared identifier

   using namespace NAME;            // далее n1 и n2 доступны

   n2=4;             

   cout << n1 <<"  "<< n2 << endl;  // результат  3  4

   { n1=5;

      n2=6;

      cout << n1 <<"  "<< n2 << endl;   // результат 5  6

   }

   return 0;

  }

В результате выполнения программы получим:

3   4

5   6

Область  действия  директивы using  распространяется  на  блок,  в котором

она использована, и на все вложенные блоки.

Если  одно из имен  относится  к  глобальной  области,  а другое объявлено 

внутри пространства имен, то возникает неоднозначность. Это проявится только

при использовании  этого имени, а не при объявлении.

#include <iostream>

using namespace std;

В  данном  фрагменте  стандартный  заголовочный  файл  библиотеки  вво-

да/вывода iostream не имеет  расширения. Все  содержимое  этого файла определяется как часть namespace std.  Для  достижения  переносимости  рекомендуется  использовать  директиву using,  хотя  и  существуют  компиляторы,  не  поддерживающие  данную  возможность. Основная проблема, которую призвана решить такая конструкция это не-

зависимость от ограничения на длину имени файла  в различных операционных системах.  Более  того,   компиляторы  Microsoft  последних  версий  вообще  не поддерживают вариант с подключением файлов стандартной библиотеки с  расширением  .h, т.е. конструкция #include <iostream.h> в Visual C++ 7.1 не компилируется.

       Ключевое слово using как объявление.

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

явления  некоторого  имени (из  пространства  имен)  как принадлежащего  текущей области действия (блоку). 

#include <iostream>

using namespace std;

namespace NAME

{ int n1=1;

   int n2=2;

}

int main()

{ NAME::n1=3;

  // n1=4;   error  'n1' надо указывать полностью  NAME::n1   

  // n2=5;   error  'n2' : undeclared identifier  

  // int n2;         следующая строка приводит к ошибке    

  using NAME::n2;            // далее n2 доступно

  n2=6;             

  cout <<NAME::n1<<"  "<< n2 << endl;  // результат  3  6

  { NAME::n1=7;

    n2=8;

    cout <<NAME::n1<<"  "<< n2 << endl;// результат  7  8

  }

  return 0;

}

В результате выполнения программы получим:

3   6

7   8

Объявление using добавляет определенное имя в  текущую область дейст-

вия. В примере  к переменной n2 можно обращаться без указания принадлежности  классу,  а  для  n1  необходимо  полное  имя.  Объявление  using  обеспечивает более подробное управление именами, переносимыми в пространство имен. Это и  есть  ее  основное  отличие  от  директивы,  которая переносит все имена пространства имен. Внесение в локальную область (блок) имени, для которого выполнено явное объявление (и наоборот), является серьезной ошибкой.

 
 
 
 
 
 

41.Виртуальные функции

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

а затем вверх  по иерархии до деструктора базового класса.

class Shape                 

{protected:

    double s;                      

public:

    Shape(char *fig) : s(0)

    { cout << " конструктор класса Shape  (фигура "<< fig <<')'<< endl;}

    virtual ~Shape()

    { cout << " деструктор класса Shape " << endl;}

Информация о работе Шпаргалка по "Программированию"