Do tej pory programy pisane były w oparciu o jedną strukturę. Tym niemniej obecna filozofia programowania wyróżnia tzw. podejście obiektowe, gdzie program można podzielić na części składowe w postaci obiektów komunikujące się ze sobą w różnorodny sposób.

Oby wprowadzić pojęcie obiektu wpierw musimy uzgodnić pojęcie klasy, czyli elementu programistycznego zawierającego w sobie definicje zmiennych i metod w postaci funkcji czy procedur. Z innej strony klasa to zazwyczaj grupa elementów ściśle z siebie nawzajem wynikających, współpracujących ze sobą, powiązanych wzajemnymi relacjami, związanych z konkretną funkcjonalnością itp. którą to programista zechciał scalić w jednej strukturze logicznej. Z definicji klasy wynika definicja obiektów, które są po prostu fizycznymi, czyli “powołanymi do życia” instancjami klasy. Tak jak zmienna jest instancją danego typu, tak i obiekt jest instancją danej klasy, do których to możemy się odwoływać i używać. Tak jak nie możemy użyć po prostu typu, tak i nie możemy użyć od razu klasy – wpierw trzeba stworzyć zmienną danego typu, czy obiekt danej klasy.

Poniżej przedstawiony został program będący przykładem definicji klasy i powołania jej do życia.

#include <iostream>
//#include <sstream>
#include <windows.h>
using namespace std;

class Owoc {
	private:
		int stopienDojrzalosci;
		string kolor;
	public:
		string nazwa;
 Owoc() {
	cout << "Uruchomiono: Konstruktor bezparametrowy obiektu..." << endl;
	stopienDojrzalosci=0;
	nazwa="nazwij mnie";
	kolor="pokoloruj mnie";
	}
	
 void setDojrzalosc(int Dojrzalosc)	{
	if (Dojrzalosc>=0 && Dojrzalosc<=100) 
		stopienDojrzalosci=Dojrzalosc;
//metoda będąca tzw. setterem - czyli ustawiająca jakąś wartość w ramach klasy - tutaj zmienną stopienDojrzalosci.
					}
	
 int getDojrzalosc () 	{
	return stopienDojrzalosci;
// metoda będąca tzw. getterem - czyli zwracająca jakąś wartość wynikającą z jej wewnętrznego kodu, tutaj stopienDojrzalosci.
			}

 ~Owoc() {
	cout << "Uruchomiono: Destruktor obiektu..." <<endl;
 	 }		
};


int main()
{
    SetConsoleCP( 852 );
    setlocale ( LC_ALL, "" );

	Owoc owoc;  //powołanie do życia obiektu owoc klasy Owoc.
	
	cout << owoc.nazwa << endl;
	owoc.setDojrzalosc(owoc.getDojrzalosc()+1);
	owoc.nazwa = "Jabłko";
	cout << owoc.nazwa << " jest już dojrzałe na " << owoc.getDojrzalosc() << "%" << endl;

    return 0;
}

Tworząc obiekt wpierw uruchamiana jest specjalna metoda: konstruktor, który może być jawny, bądź niejawny (zawsze jest!). Jeśli jest jawny (metoda klasy o nazwie identycznej z nazwą klasy), czyli zdefiniowany przez programistę, to w jego ciele mogą się znaleźć specyficzny kod programu ustawiający obiekt do stanu “wyjściowego” do dalszej jego pracy. Obiekt, kończąc życie, np. z końcem programu jest “niszczony” za pomocą destruktora niejawnego, bądź jeśli potrzebujemy w jakiś konkretny sposób podejść do tego tematu, to możemy zdefiniować w klasie destruktor jawny (metoda o nazwie identycznej z nazwą klasy poprzedzona znakiem “~” ). Pozostałe metody w ramach klasy można nazwać w zależności od ich funkcjonalności jako settery (jeśli coś ustawiają w obiekcie) lub gettery (jeśli pobierają i udostępniają “na zewnątrz” jakieś wartości). Klasa może jak najbardziej zawierać dowolne inne metody o swoistej dla nich funkcjonalności.

Powołanie obiektu do życia jest przedstawione w metodzie main(), a użycie zmiennych i metod poniżej tego.

Zadanie do samodzielnego wykonania: Uruchom program i poeksperymentuj zmieniając jego dane, spróbuj ustawić różne wartości, wyświetlać je. Zaproponuj własną klasę i spróbuj ją oprogramować.

W konstruktorze użyliśmy operatorów przypisania aby ustawić początkowe wartości obiektu, ale nie jest to najlepszy sposób. Bardziej właściwym z uwagi na kolejność przypisywania w trakcie tworzenia obiektu jest tzw. lista inicjalizacyjna. Może się bowiem zdarzyć, że spróbujemy użyć obiektu zaraz po jego stworzeniu, ale proces przypisywania wartości w konstruktorze jeszcze się nie zakończył – spowoduje to błędy w działaniu programu. Lista inicjalizacyjna powoduje, że przy tworzeniu obiektu wartości są od razu przypisywane jednocześnie ze stworzeniem odpowiadających im zmiennych. Inną cechą przemawiającą za listą inicjalizacyjną jest nadanie wartości stałej występującej w obiekcie. Jak wiadomo nie da się zmienić wartości zmiennej powołanej jako stała i wartość ta nadawana jest w trakcie powstawania owej zmiennej (i obiektu). Oczywiście można by było wpisać ową wartość w definicję klasy, ale co jeśli wartość tej stałej musi być każdorazowo obliczona w momencie tworzenia obiektu?! Lista inicjalizacyjna jest także niezbędna przy inicjowaniu zmiennych zdefiniowanych jako referencje np.: int& zmienna; oraz jest metodą stosowaną przy dziedziczeniu klas

Modyfikacja konstruktora wyglądałaby następująco:

Owoc():stopienDojrzalosci(0),nazwa("nazwij mnie"),kolor("pokoloruj mnie")	 {
	cout << "Uruchomiono: Konstruktor bezparametrowy obiektu..." << endl;		
	}

A z użyciem wspomnianej stałej:

class Owoc {
	private:
		int stopienDojrzalosci;
		string kolor;
		const string jadalny;  // wprowadziliśmy stałą
	public:
		string nazwa;
 Owoc():stopienDojrzalosci(0),nazwa("nazwij mnie"),kolor("pokoloruj mnie")	 {
	cout << "Uruchomiono: Konstruktor bezparametrowy obiektu..." << endl;		
	}

 Owoc(string czyJadalny):stopienDojrzalosci(0),nazwa("nazwij mnie"),kolor("pokoloruj mnie"),jadalny(czyJadalny)	 {
	cout << "Uruchomiono: Konstruktor bezparametrowy obiektu..." << endl;		
	//jadalny=czyJadalny;  // <- tutaj to nie zadziała, bowiem nie można modyfikować stałej, ale w liście inicjalizacyjnej powyżej już tak...		
	}
...

Lista inicjalizacyjna umożliwiła nam nadanie właściwych wartości konkretnemu obiektowi. Przy okazji okazało się, że mogą być dwa (i więcej) konstruktory. Ważne jest przy tym aby były rozróżnialne ilością i/lub typem parametrów, co znaczy, że nie mogą być dwa identycznie wywoływane (niezależnie od ich kodu). To samo dotyczy metod – jest to często spotykane w programowaniu i nazywa się przeciążaniem metod. Dzięki temu nie trzeba tworzyć różnych nazw metod przy podawaniu argumentów o różniących się typach – program w trakcie działania sam dopasuje odpowiednią metodę na podstawie typu argumentów.

Zadanie do samodzielnego wykonania: Stwórz w ramach testowego obiektu kilka metod o tych samych nazwach ale różniących się wartością zwracaną i typem/ilością argumentów.

Jeśli nie masz pomysłu na program wykorzystaj pomysł na kalkulator, gdzie zdefiniuj klasę Kalkulator zawierającą wybrane przez Ciebie operacje matematyczne w postaci metod np.: dodawanie, odejmowanie itp. Spróbuj zdefiniować je tak aby możliwe były operacje bez zmiany typu argumentów np. jeśli podajemy do zsumowania liczby typu int, niech wynikiem również jest int; jeśli na wejście podamy float, to niech typem zwracanym jest również float. Pokuś się o zdefiniowanie metod o zmiennej liczbie parametrów (ang. variable-length argument list).

Z początkowego kodu wynika jeszcze jedna niewiadoma – a mianowicie deskryptory zasięgu public, private protected. Związane są one z dostępem do wnętrza obiektu. Tak jak konstruktor destruktor musi być publiczny, tak inne metody (i zmienne) mogą być public, albo też private lub protected, czyli niedostępne z zewnątrz obiektu. Po co ograniczać dostęp? Najprostszym wyjaśnieniem jest dbałość o hermetyczność obiektu i poprawność danych do niego wprowadzanych – zerknij na setter setDojrzałość() – jego konstrukcja wyjawia, że zmienna stopienDojrzalosci zostanie ustawiona jedynie w przypadku jeśli w argumencie podamy wartość pomiędzy 0 a 100 (w domyśle %). Jak widać mamy weryfikację (walidację) danych zanim wprowadzimy je do obiektu. To samo możemy zrobić z każdą daną i metodą – to programista ustala do czego ma dostęp użytkownik spoza obiektu. Czym się różni wobec tego public od private czy protected już wiadomo, ale czym się różnią private od protected jest związane z zagadnieniem dziedziczenia i wtedy zostanie to wyjaśnione.