#include <iostream.h>
#include "Deriv.hpp"

int main(void)
{
    //Obiect de tipul Base1.
    Base1       B1_1;
    //Se citeste valoarea obiectului in stream-ul de intrare.
    cin >> B1_1;
    //Se initializeaza B1_2 de tipul Base1 ca o copie a lui B1_1.
    Base1       B1_2(B1_1);
    //Obiect de tipul Base1
    Base1       B1_3;
    //Lui B1_3 i se atribuie rezultatul sumei dintre B1_1 si B1_2.
    B1_3 = B1_1 + B1_2;
    cout << "B1_3 = B1_1 + B1_2" << endl;
    cout << "B1_3" << endl << B1_3;
    cout << "B1_1" << endl << B1_1;
    cout << "B1_2" << endl << B1_2;
    //Obiect de tipul Base2.
    Base2       B2_1;
    //Se citeste valoarea obiectului in stream-ul de intrare.
    cin >> B2_1;
    //Se initializeaza B2_2 de tipul Base2 ca o copie a lui B2_1.
    Base2       B2_2(B2_1);
    //Obiect de tipul Base2.
    Base2       B2_3;
    //Lui B2_3 i se atribuie rezultatul sumei dintre B2_1 si B2_2.
    B2_3 = B2_1 + B2_2;
    cout << "B2_3 = B2_1 + B2_2" << endl;
    cout << "B2_3" << endl << B2_3;
    cout << "B2_1" << endl << B2_1;
    cout << "B2_2" << endl << B2_2;
    //Obiect de tipul Deriv.
    Deriv       D1;
    //Se citeste valoarea obiectului in stream-ul de intrare.
    cin >> D1;
    //Se initializeaza D2 de tipul Deriv ca o copie a lui D1.
    Deriv       D2(D1);
    //Obiect de tipul Deriv.
    Deriv       D3;
    //Lui D3 i se atribuie rezultatul sumei dintre D1 si D2.
    D3 = D1 + D2;
    cout << "D3 = D1 + D2" << endl;
    cout << "D3" << endl << D3;
    cout << "D1" << endl << D1;
    cout << "D2" << endl << D2;
    //Sa incercam si ceva polimorfism ...
    Base1       *PtrBase1;
    Base2       *PtrBase2;
    PtrBase1 = &D3;
    //Apel la operator prin invocarea numelui ca functie.
    cout << PtrBase1->operator ()(10) << endl;
    //Sau
    cout << (*PtrBase1)(10) << endl;
    //Apel la metoda virtuala a clasei de baza cu ajutorul
    //operatorului de rezolutie si calificarea explicita.
    cout << PtrBase1->Base1::operator ()(10) << endl;
    PtrBase2 = &D3;
    //Apel la operator prin invocarea numelui ca functie.
    cout << PtrBase2->operator ()(10) << endl;
    //Sau
    cout << (*PtrBase2)(10) << endl;
    //Apel la metoda virtuala a clasei de baza cu ajutorul
    //operatorului de rezolutie si calificarea explicita.
    cout << PtrBase2->Base2::operator ()(10) << endl;
    //Atentie !!! Exista o serie de operatori functie care supradefinesc
    //operatorii functie virtuali. In acest caz nu este vorba de polimorfism.
    //Se apeleaza operatorul corespunzator lui Base1
    //pe baza partii din D2 care a fost mostenita de la Base1.
    cout << (*PtrBase1)(10, 10) << endl;
    //Se apeleaza operatorul corespunzator lui Base2
    //pe baza partii din D2 care a fost mostenita de la Base2.
    cout << (*PtrBase2)(-10, -10) << endl;
    //Se apeleaza operatorul corespunzator lui Deriv.
    cout << D3(10, 10) << endl;
    //In utlimele trei cazuri este vorba de supradefinirea operatorului
    //operator ()(int,int) si domeniul sau de vizibilitate.
    //Pentru apelul diferitelor metode disponibile in acest caz
    //utilizati cu incredere operatorul de rezolutie si calificare
    //prin numele clasei.
    cout << D3.Base1::operator ()(10, 10) << endl;
    cout << D3.Base2::operator ()(10, 10) << endl;
    cout << D3(10, 10);
    cin.get();
    return 1;
}
