piątek, 4 kwietnia 2014

Operatory rzutowania w C++

#include <iostream>

using std::cout;

using std::cin;

using std::endl;

class object_one { };

class object_two : public object_one { };

class object_three {
public:
    short variable_1;
    short variable_2;
};

int main() {
    // Operator dynamic_cast. Jego zadaniem jest umożliwienie (lub nie) rzutowania w górę wewnątrz hierarchii klas.

    object_one first_object_one;
    object_two first_object_two;
    object_one * pointer_object_one;
    object_two * pointer_object_two = & first_object_two;

    pointer_object_one = dynamic_cast<object_one *>(pointer_object_two);

    if (pointer_object_one != nullptr)
        cout << "Udalo sie rzutowac za pomoca dynamic_cast.\n";
    else
        cout << "Nie udalo sie rzutowac za pomoca dynamic_cast.\n";

    // Operator const_cast. Służy do rzutowania typu, którego jedynym celem jest zmiana etykiety wartości między "const" a "volatile". Przydomek "volatile" mowi kompilatorowi, że ma być ostrożony w kontaktach z danym obiektem. Słowo to ostrzega, że obiekt może się w jakiś niezauważalny dla kompilatora sposób zmieniać. Kompilator nie powinien sobie upraszczać sprawy tylko za każdym razem zwracać się do przydzielonych temu obiektowi komórek pamięci.

    const object_two * const_pointer_object_two = & first_object_two;

    pointer_object_two = const_cast<object_two *>(const_pointer_object_two); // Wskaźnik "pointer_object_two" może teraz zostać użyty do zmiany wartości obiektu "first_object_two" (usunięcie etykiety "const").

    // "const object_one * const_pointer_object_one = const_cast<const object_one *>(const_pointer_object_two);" - to wyrażenie jest niepoprawne gdyż próbuje zmienić z typu "const object_two *" na "const object_one *".

    // Operator static_cast.

    pointer_object_one = static_cast<object_one *>(& first_object_two); // Rzutowanie w górę.
  
    pointer_object_two = static_cast<object_two *>(& first_object_one); // Rzutowanie w dół.

    if (pointer_object_one != nullptr)
        cout << "Udalo sie rzutowac w gore za pomoca static_cast.\n";
    else
        cout << "Nie udalo sie rzutowac w gore za pomoca static_cast.\n";

    // object_three * pointer_object_three = static_cast<object_three *>(& first_object_two); // Niepoprawne gdyż klasa object_three jest poza hierarchią.

    // Operator reinterpret_cast. Służy do ryzykownych operacji jak np. rzutowanie typu wskaźnikowego na typ całkowity, który jest wystarczająco pojemny aby pomieścić reprezentację wskaźnika. Nie możemy jednak rzutować wskaźnika na mniej pojemny typ liczby całkowitej lub na typ zmiennoprzecinkowy czy też rzutować wskaźnik na funkcję na wskaźnik na dane i odwrotnie.

    long value = 0xa224b118;

    object_three * pointer_object_three = reinterpret_cast<object_three *>(&value);

    cout << "Dwa pierwsze bajty wartosci: " << std::hex << pointer_object_three->variable_1 << endl;
}

Źródło: Prata S., Język C++. Szkoła programowania. Wydanie VI, Helion SA, 2012