virtualna funkcja operatorowa

0

Witam, napotkałem na swojej programistycznej drodze kolejny problem, a bez waszej wiedzy i doświadczenia będę stał w miejscu:). Napisałem program czysto hipotetyczny obrazujący problem jaki napotkałem w bardziej rozbudowanym programie

Opis Zagadnienia
Klasa Figura musi być klasą abstrakcyjną ma wiele więcej innych metod czysto wirtualnych których dla uproszczenia nie dodawałem.
zależy mi na wyświetlaniu wyników dodawania raz obiektów Klasy Kolo, a innym razem obiektów klasy np Trójkąt, (realizacja dodawania tych klas rożni się od siebie.), przydatna będzie w takim razie funkcja "Wyświetl", uniwersalna dla obu klas.
Chciałbym napisać ją tylko raz dla obu Klas. Z racji że Klasa Bazowa jest abstrakcyjna, to przesyłam argumenty tej funkcji jako referencje.

Opis Problemu:

  1. Po odkodowaniu linijki
// cout <<"Gdy mnie odkomentujesz bede dzialac !\n"; 

Program działa.
a zakomentowany zawiesza sie :).

  1. Ostrzeżenie jakie dostaję
    'wynik' is used uninitialized in this function [-Wuninitialized]|

Kod

#include <iostream>
using namespace std;


class Figura
{
public:
    int a;
public:

    virtual Figura & operator+(Figura &bryla)=0;
};
//********************************************************************************

class Trojkat : public Figura
{
public:
    Trojkat()
    {
        a=1;
    }
    friend ostream & operator <<(ostream & napis, Figura &bryla);
    virtual void czystoWirtualna() {};

    virtual Figura & operator+(Figura &bryla)
    {
        // cout <<"Gdy mnie odkomentujesz bede dzialac !\n";
        Figura * wynik;
        wynik->a = this->a + bryla.a + 100; // troche inna operacja
        return *wynik;
    }
};
//********************************************************************************

// Ta funkcja operatorwa dla kazdej klasy pochodnej bedzie taka sama
ostream & operator <<(ostream & napis, Figura &bryla)
{
    napis <<  bryla.a;
    return napis;
}

//********************************************************************************
// Chce aby funkcja byla uniwersalna dla Kazdej z pochodnych Klas od Figury, zalozmy zejest bardzo skomplikowana
void Wyswietl(Figura & f1, Figura & f2)
{
    cout << f1 + f2;
}
//********************************************************************************

int main()
{
    Figura *wsk1, *wsk2;
    Trojkat t1, t2;

    wsk1 = &t1;
    wsk2 = &t2;
    cout << "t1= "<< t1 << endl << "t2= " << t2 << endl;
    Wyswietl(*wsk1, *wsk2);
}
 

Dziękuję za odpowiedzi i pozdrawiam;

1
  1. Po odkodowaniu linijki
    // cout <<"Gdy mnie odkomentujesz bede dzialac !\n";
    Program działa.
    a zakomentowany zawiesza sie :).

przypadek nic wiecej

 
Figura * wynik;
wynik->a = this->a + bryla.a + 100; // troche inna operacja
return *wynik;

powiedz mi na co tutaj wskazuje wynik?

2

ostrzeżenie dokładnie mówi w czym problem!
Używasz nieustalonej wartości wskaźnika wynik, który wskazuje na jakiś śmieć. Jeśli odkomentujesz cout to przez przypadek ten śmieć ma sensowną wartość (stara wartość z użyta dla cout ma wpływ na wartość śmieciowej wartości).

Problem polega na tym, że chcąc skorzystać z polimorfizmu przy operatorze dodawania wkopałeś się w kłopoty z zarządzaniem pamięcią. Jeśli chcesz to jakoś obejść to musisz użyć jakiś mądrych wskaźników (dla c++11 shared_ptr, dla C++03 boost lub własne rozwiązanie). IMO za wysokie progi na twoje nogi.
Lepiej będzie, jak operator dodawania nie będzie wirtualną metodą.

0

rzeczywiście nie pomyślałem, o możliwości dodania snopowiązałki do budynku opery :D.

Swoją drogą, w jaki sposób mogę sprawdzić informacje o typie na jaki wskaźnik aktualnie pokazuje ?

if(wsk pokazuje na Kolo)
//
else if(wsk pokazuje na Trojkat)
// 
1

jezeli musisz cos takiego robic (ze sprawdzac na co wskazuje) to masz blad a architekturze i to powazny

ale jak potrzebujesz to tutaj masz
http://en.cppreference.com/w/cpp/language/typeid

1

Widzę, że systematycznie dajemy dziecku brzytwę.
Daruj sobie polimorfizm dla operatorów, a jeszcze lepiej napisz to zupełnie bez definiowania własnych operatorów.
Ja wiem, że operatory to taki ładny błyszczący feature języka, ale zapewniam cię, nie jest ci to potrzebne do stworzenia porządnego i poprawnie działającego kodu.

0

Zrezygnowałem z wirtualnych operatorów. Niestety muszę użyć operatory(te nie wirtualne) tak czy siak w moim programie - z góry narzucone.

Opis Programu
Użytkownik dokonuje wyboru na czym chce wykonywać operacje. Ustawiam wskaźnik(typu Algebra) wtedy na obiekty tego typu(Wielomian/Wielomian Binarny).
Metoda WprowadzDane() to metoda czysto wirtualna z klasy Bazowej Algebra, po niej dziedziczą Wielomiany i wielomiany Binarne.
Ekstra dzięki wirtualności mogę wywołać metodę WprowadzDane() w zależnośći na to na jaki obiekt pokazuje teraz wskaźnik. Ale co z tego. skoro nadal nie mogę dokonywać operacji +,-,* Bo przecież klasa Algebra nie ma takich operatorów.
A nawet jak je zdefiniuje to będę mógł dodać Wielomian do Wielomianu Binarnego - bezsens.

nic dziwnego
error: no match for 'operator+' (operand types are 'Algebra' and 'Algebra')|

Podsumowanie
Chcę w programie inteligentnym wskaźnikiem wprowadzić dane, a następnie wywołać operator

 WielomianyBinarne operator+(WielomianyBinarne dodawany)

lub

 Wielomian operator+(Wielomian dodawany) 

w zależności od zmiennej wybór.

Obrazując:
Czyli: Hej wskaźniku jesteś typem Algebra ale teraz pokazujesz na typ Wielomiany, widzisz "+" dwóch wielomianów to uruchom

 Wielomian operator+(Wielomian dodawany)
 
bool OperacjeWielomianowe(int &wybor) // przesylamy nasz wybor czy uzytkownik wybral Wielomiany czy WielomianyBinarne
{
    Algebra *wsk1, *wsk2;     // wskaznikiem bedziemy pokazywac na wybrana operacje czy to wielomiany czy wielomiany binarne
    Wielomian w1, w2;         // tworzymy  wielomiany wypelnione zerem
    WielomianyBinarne b1, b2; // tworzymy  wielomiany binarne wypelnione zerem

    if(wybor == 1)
        wsk1 = & w1, wsk2 =& w2; // ustawiamy wskazniki na Wielomiany
    else // w innym przypadku czyli 2
        wsk1 = & b1, wsk2 =& b2; // ustawiamy wskazniki na Wielomiany binarne


    int key;
    while(1)
    {
        //system("cls"); // czyscimy ekran
        cout << "=================================\n";
        cout << "w1 + w2= " << *wsk1 + *wsk2 << endl;
        cout << "w1 - w2= " << *wsk1 - *wsk2 << endl;
        cout << "w1 * w2= " << *wsk1 * *wsk2 << endl;
        cout << "=================================\n\n";
        cout << "1) Wprowadz Wielomiany \n";
        cout << "2) Powrot \n";

        cin >> key;

        switch (key)
        {
        case 1:
        {
            cout<<"Wprowadz Dane pierwszego Wielomianu: \n";
            wsk1->WprowadzDane(); // wykorzystujemy sprytny wskaznik ktory patrzy na to na jaki tym jest ustawiony a nie na to jakim typem jest on sam. dzieki fun Wirtualnej
            cout<<"Wprowadz Dane drugiego Wielomianu: \n";
            wsk2->WprowadzDane(); // wykorzystujemy sprytny wskaznik ktory patrzy na to na jaki tym jest ustawiony a nie na to jakim typem jest on sam. dzieki fun Wirtualnej
            break;
        }
        case 2:
            return true;
        default:
            cout << "Nie ma takiej operacji\n";
        }
    }
}
//****************************************************************

class Algebra
{
protected:
    double *wspolczynniki;
    int stopien;
public:
        virtual void WprowadzDane()=0;
};

//****************************************************************
class WielomianyBinarne : public Algebra
{
//...
public:

    WielomianyBinarne operator+(WielomianyBinarne dodawany)
    {
        return wynik;
    }
 virtual void WprowadzDane(){};
};
//******************************************************************
class Wielomian : public Algebra
{
//...
public:

    Wielomian operator+(Wielomian dodawany)
    {
        return wynik;
    }
virtual void WprowadzDane(){};
};

1 użytkowników online, w tym zalogowanych: 0, gości: 1