Что такое ООП?

Объектно-ориентированное программирование — это новый подход к созданию программ. ООП использует лучшие идеи, воплощенные в структурном программировании, и сочетает их с мощными новыми концепциями, которые позволяют оптимально организовывать ваши программы. Объектно-ориентированное программирование позволяет вам разложить проблему на составные части. Каждая составляющая становится самостоятельным объектом, содержащим свои собственные коды и данные, которые относятся к этому объекту. В этом случае вся процедура в целом упрощается, и программист получает возможность оперировать с гораздо большими по объему программами. Все языки ООП, включая C++, основаны на трех основополагающих концепциях, называемых инкапсуляцией, полиморфизмом и наследованием.

Что такое класс? Что такое объект? В чем разница?

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

Какие существуют модификаторы уровня доступа?

Public — открытый. Все методы и свойства , объявленные после этого модификатора доступны из любой части программы. Private — закрытый. Методы и свойства, уровня доступа private разрешено использовать только внутри класса, запрещено использование в производных классах. Protected — защищенный. Эквивалентен модификатору private с единственным исключением: разрешено использование методов и свойств в производных классах.

Что такое наследование?

Наследование — это процесс, посредством которого один объект может приобретать свойства другого. Объект может наследовать свойства другого объекта и добавлять к ним черты, характерные только для него. Применительно к C++ наследование — это механизм, посредством которого один класс может наследовать свойства другого. Наследование позволяет строить иерархию классов, переходя от более общих к более специальным. Когда один класс наследуется другим, класс, который наследуется, называют базовым классом (base class). Наследующий класс называют производным классом (derived class). Обычно процесс наследования начинается с задания базового класса. Базовый класс определяет все те качества, которые будут общими для всех производных от него классов. В сущности, базовый класс представляет собой наиболее общее описание ряда характерных черт. Производный класс наследует эти общие черты и добавляет свойства, характерные только для него.

Если мы наследуем класс, наследуются ли приватные поля (члены)?

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

Что означает модификатор virtual?

Виртуальная функция (virtual function) является членом класса. Она объявляется внутри базового класса и переопределяется в производном классе. Для того, чтобы функция стала виртуальной, перед объявлением функции ставится ключевое слово virtual. Если класс, содержащий виртуальную функцию, наследуется, то в производном классе виртуальная функция переопределяется. По существу, виртуальная функция реализует идею “один интерфейс, множество методов”, которая лежит в основе полиморфизма. Виртуальная функция внутри базового класса определяет вид интерфейса этой функции. Каждое переопределение виртуальной функции в производном классе определяет ее реализацию, связанную со спецификой производного класса. Таким образом, переопределение создает конкретный метод. При переопределении виртуальной функции в производном классе, ключевое слово virtual не требуется.
Приведем пример:
Пусть имеется базовый класс base, от которого наследуется производный класс derived
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class base
{
   public:
   void func(void)
   {
     cout << "Вызван метод базового класса base\n";
     return;
   }
};
 
class derived: public base
{
   public:
   void func(void)
   {
     cout << "Вызван метод производного класса derived\n";
     return;
   }
};

Теперь посмотрим на следующий код:

base *p; // объявляем указатель на базовый класс base
derived d_ob;
p=&d_ob; //указателю присваиваем адрес объекта производного класса derived
p->func(); //вызываем метод

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

Вызван метод базового класса base

Здесь мы присвоили указателю адрес объекта производного класса, но при вызове метода func выполняется код из метода базового класса base. Если же мы объявим в базовом классе виртуальный метод, то компилятор во время выполнения вызовет метод адресуемого объекта.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class base
{
   public:
   virtual void func(void)
   {
     cout << "Вызван метод базового класса base\n";
     return;
   }
};
 
class derived: public base
{
   public:
   void func(void)
   {
     cout << "Вызван метод производного класса derived\n";
     return;
   }
};

Теперь в результате выполнения кода получим:

Вызван метод производного класса derived


Что такое абстрактный класс. Можно ли создать экземпляр абстрактного класса?

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

Что такое инкапсуляция?

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

Что такое полиморфизм. Какими средствами языка он реализуется?

Полиморфизм — это механизм, который позволяет использовать одно и то же имя для реализации различных задач. Смысл полиморфизма можно описать одной фразой: «Один интерфейс, множество методов». Реализация полиморфизма заключается в том, что в производном классе переопределяют метод базового класса, при этом сохраняя описание метода. Такой подход позволяет связать название метода с разными классами и вызывать метод того класса, объект которого в данный момент используется.

Что такое виртуальный деструктор?

Виртуальный деструктор объявляется вместе с ключевым словом virtual. Он необходим для того, чтобы при удалении указателя на объект вызывался деструктор именного этого объекта. Приведем пример для 2-х классов — базового base и производного derived:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class base
{
    public:
     ~base()
    {
      cout << "Вызван деструктор базового класса base\n";
    }
  };
 
class derived: public base
{
  public:
   ~derived()
  {
    cout << "Вызван деструктор производного класса derived\n";
  }
};

Теперь, выполним следующий код:

1
2
3
4
5
  base *p; // объявляем указатель на базовый класс base
  derived d_ob;
  p=new derived(); // присваиваем указателю адрес объекта производного объекта derived
  delete p; // удаляем объект, на который ссылается указатель
  return 0;
В результате увидим, что выполнится деструктор базового класса, а не производного. Такая ситуация может привести к утечке памяти. Решением проблемы служит виртуальный деструктор. Если перед объявлением деструкторов базового и производного классов поставить ключевое слово virtual, то в результате выполнения приведенного кода выполниться деструктор производного класса.

Что такое виртуальный конструктор?

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