Programowanie obiektowe w C++

Opublikowane: 27/11/2014

w kategorii Zasoby.

Programowanie zorientowane obiektowo (OOP - Object Oriented Programming) jest czymś czego naucza się w wielu szkołach, chociaż być może nie jest to tak użyteczne dla początkujących. Jest to metoda programowania której głównym celem jest tworzenie lepszego kodu dla programistów utrzymujących kod.

W OOP kod jest zorganizowany w klasy lub struktury które wiążą atrybuty danych z funkcjami które mogą na nich operować. Obiekt jest instancją klasy lub struktury i każda instancja może mieć unikalne wartości atrybutów.

Jest kilka ważnych tematów związanych z OOP:

  • dziedziczenie: mechanizm reużywania kodu pomiędzy klasami
  • polimorfizm: pozwala na dostęp do klasy pochodnej używając wskaźnika na klasę bazową, użyteczne w funkcjach które mogą pracować na całym drzewie dziedziczenia
  • enkapsulacja: ukrywanie atrybutów klasy i jej metod chyba że są wymagane przez świat zewnętrzny
  • kompozycja: przechowywanie jednego lub więcej obiektów wewnątrz innego
  • wirtualne dziedziczenie: temat związany ściśle z C++ i wielo-bazowym dziedziczeniem
  • czyste wirtualne (abstrakcyjne) funkcje: funkcje które muszą być zaimplementowane w klasach pochodnych
  • klasy abstrakcyjne: klasy z abstrakcyjnymi metodami
  • funkcje zaprzyjaźnione: funkcje które mogą dostać się do prywatnych atrybutów klasy
  • klasy finalne: klasy z których nie można dziedziczyć
  • atrybuty klas: atrybuty które mają taką samą wartość dla każdego z obiektów

Przykładowa klasa może być zdefiniowana następująco:

#include <iostream>
#include <string>
using namespace std;

class scBaseTask
{
  // atrybut obiektu: każdy obiekt ma swoją kopię zmiennej z unikalnym adresem w pamięci
  bool running;

  public:
  // konstruktor: wykonywany kiedy tworozny jest nowy obiekt (zaalokowany w pamięci)
    scBaseTask():running(false) {}

  // destruktor: wykonywany kiedy obiekt ma zostać usunięty z pamięci
    virtual ~scBaseTask() {}

  // --- metody ---

  // metoda wirtualna może zostać zastąpiona w klasie pochodnej
    virtual std::string getName() { return "BaseTask"; }

  // metody nie-wirtualne nie mogą być zastąpione w klasach pochodnych ale nadal mogą być dostępne.
    bool isRunning() { 
      return running; 
    }

    void start() { 
      if (!running) {
        cout << "Zadanie [" << getName() << "] wystartowane\n";
        running = true; 
      }
    }

    void stop() { 
      if (running) {
        cout << "Zadanie [" << getName() << "] zatrzymane\n";
        running = false; 
      }
    }
};

// klasa pochodna, implementuje pochodną klasę, zawiera nową wersję "getName" 
class scSortTask: public scBaseTask {
  public:
    virtual std::string getName() { return "SortTask"; }
};

int main() {
    scBaseTask baseTask;
    baseTask.start();
    if (baseTask.isRunning())
      cout << "baseTask jest uruchomione\n";
    baseTask.stop();
    scSortTask sortTask;
    scBaseTask *baseTaskPtr = &sortTask;
    // test polimorfizmu: wywołuje metodę klasy pochodnej używając wskaźnika do klasy bazowej
    cout << "Zadanie Sort zwraca nazwę: " << baseTaskPtr->getName() << "\n";
    return 0;
}

Wynik:
Zadanie [BaseTask] wystartowane
baseTask jest uruchomione
Zadanie [BaseTask] zatrzymane
Zadanie Sort zwraca nazwe: SortTask

Klasy finalne

Klasy dla których nie możesz zaimplementować klas dziedziczących. Użyteczne w klasach implementujących API.

wersja 1

class Temp
{
private:
  ~Temp() { };
  friend class FinalClass;
};

class FinalClass : virtual public Temp
{
. . .
};

wersja 2

// bazuje na: API Design for C++, Martin Reddy
class NoBase 
{
    public:
      static NoBase* Create() { return new NoBase(); }
    private:
      NoBase();  
};

wersja 3 - przy pomocy szablonów

template <typename T>
class MakeFinal
{
private:
  ~MakeFinal() { };
  friend T;
};

class FinalClass : virtual public MakeFinal<FinalClass>
{
};

Interfejsy

Zobacz Interfejsy w C++.

Zasoby

Zobacz także

Udostępnij

obserwuj