Wątek przeniesiony 2015-05-21 13:03 z C/C++ przez ŁF.

Program służący do wybierania i generowania częstotliwości.

0

Jak że jest to mój pierwszy post na forum to chciałbym się serdecznie przywitać, Cześć!
Piszę program który ma wybierać częstotliwość, po czym ją generować, pobierać odpowiedź i sprawdzać poprawność.
Właśnie jestem w trakcie jego pisania. Postanowiłem go podzielić na 2 (a w zasadzie 3) główne moduły: Freq, Test, no i oczywiście main.
Jako że preferuje zasade od szczegółu do ogółu to postanowiłem najpierw napisać moduł Freq, który zawiera metody losowania częstotliwości oraz jej generacji.
No i mam spore problemy, rozumiem oczywiśćie że przyczyną tego jest moja niewiedza i brak doświadczenia, dlatego piszę ten post.
Używam Code::Blocks'a z minGW, a poniżej wklejam kod z którym mam problemy.
Bardzo bym prosił kogoś uprzejmego, o ile znajdzie chwilę czasu aby zerknął w ten kod i najlepiej w miejsca komentarzy które sygnalizują moją nieporadność,
wpisał na czym polegał problem oraz przykład jego rozwiązania.
Byłbym na prawde bardzo wdzięczny.

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <windows.h>

using namespace std;

class Test
{
public:
    int number_attempts;  //ilosc prob jak bedzie trzeba wykonac , domyslnie dopoki nie bedzzie dzzialac jak powinno jest 5
    int diff_level;        //poziom trudnosci (octave/terce) , domyslnie dopoki nie bedzzie dzzialac jak powinno jest octave

    Test(int n_r=5, int d_l=0)
    {
        number_attempts=n_r;
        diff_level=d_l;
    }
};
class Freq :public Test
{
public:
    int *freq;          //wskaznik ktory ma wyluskac pierwszy element z tablicy


    Freq(int *f=0, int n_r=5, int d_l=0) :Test(n_r=5, d_l=0)  //dziedzicze kosntruktor
    {
        *freq=*f;       //nie wiem czy tak mozna
        number_attempts=n_r;
        diff_level=d_l;
    }

    void select_freq()
    {
        double octave[8] =  {25, 250, 500, 1000, 2000, 4000, 8000, 16000};
        double terce[22] = {125, 160, 200, 250, 315, 400, 500, 630, 800, 1000, 1250, 1600, 2000, 2500, 3150, 4000, 5000, 6300, 8000, 10000, 12500, 16000};
        int *liczba_octave = new int[number_attempts];
        int *liczba_terce = new int[number_attempts];

        if(diff_level==0)
        {
            for(int i = 0 ; i < number_attempts; i++)
            {
                int rand_octave =( rand() % 8 ) + 1;
                for( int j = 0 ; j <= rand_octave ; j++)
                {
                    liczba_octave[i]=octave[j+1];
                }
            }
        }

        else if(diff_level==1)
        {
            for(int i = 0 ; i < number_attempts; i++)
            {
                int rand_terce =( rand() % 22 ) + 1;
                for( int j = 0 ; j <= rand_terce ; j++)
                {
                    liczba_terce[i]=terce[j+1];
                }
            }
        }

        if(diff_level==0)
        {
            freq=&liczba_octave[0];     //przypisuje adres pierwszego elementu dla wskaznika
        }
        else if(diff_level==1)
        {
            freq=&liczba_terce[0];      //przypisuje adres pierwszego elementu dla wskaznika
        }

        delete [] liczba_octave;
        delete [] liczba_terce;
    }

    void genere_freq()
    {
        Beep(*freq,3000);           //powinno generowac dzwiek o wylosowanej wczesniej czestotliwosci, chcialem wpisac freq ale wtedy sie nie kompiluje
    }
};

int main()
{
    srand( time( NULL ) );

    Freq f1;

    f1.select_freq();                       //powinno wybierac czestotliwosc do wygenerowana, pierwszy element tablicy

    for(int i = 0 ; i <= number_attempts ; i++)  //Nie wiem jak moge przekazac zmienna number_attempts, aby petla sie wykonala tyle razy ile powinna.
    {
        f1[i];                                  //tutaj chcialbym przesuwac tablice o jedno miejsce w prawo, ale nie wiem jak skoro
        //tablica jest typu int a obiekt jest obiektem
        cout<<"Czestotliwosc numer: "<<i<<endl;
        f1.genere_freq();                       //powinno generowac czzestotliwosc
        delay(500);
    }

    system("pause");
    return 0;
}
 
1
int *freq;          //wskaznik ktory ma wyluskac pierwszy element z tablicy
Freq(int *f=0, int n_r=5, int d_l=0) :Test(n_r=5, d_l=0)  //dziedzicze kosntruktor
{
    *freq=*f;       //nie wiem czy tak mozna
  1. Jeśli f == 0 to wyłuskujesz nulla.
  2. Nawet jeśli f jest poprawnym wskaźnikiem, to niezaalokowałeś pamięci dla freq a próbujesz tam coś przypisać.
  3. Po co freq jest wskaźnikiem, a nie zwykłym intem?
for( int j = 0 ; j == rand_terce ; j++)

Nie wiem co ta pętla na robić, ale wygląda na błędną. Wykonuje się raz jeśli rand_terce == 0, ani razu w innych przypadkach.

Przecież number_attemps masz w f1.number_attemps.
Co to znaczy przesunąć tablicę w prawo? I jaką tablicę, skoro f1 jest obiektem typu Freq.

0

Co do pętli to literówka, nie wiem dla czego tak napisałem, oczywiście powinno być.

 for( int j = 0 ; j <= rand_terce ; j++) 

Dzięki za post, dużo przez to wniosłem do mojego kodu (tak myślę przynajmniej). W tym momencie mam coś takiego:

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <windows.h>

using namespace std;

class Test
{
public:
    int number_attempts;  
    int diff_level;       

    Test(int n_r=5, int d_l=0)
    {
        number_attempts=n_r;
        diff_level=d_l;
    }

    virtual void genere_freq();
    virtual void select_freq();
};
class Freq :public Test
{
public:
    int freq;         


    Freq(int f, int n_r=5, int d_l=0) :Test(n_r=5, d_l=0)  
    {
        freq=f;       
        number_attempts=n_r;
        diff_level=d_l;
    }

    void select_freq()
    {
        double octave[8] =  {25, 250, 500, 1000, 2000, 4000, 8000, 16000};
        double terce[22] = {125, 160, 200, 250, 315, 400, 500, 630, 800, 1000, 1250, 1600, 2000, 2500, 3150, 4000, 5000, 6300, 8000, 10000, 12500, 16000};
        int liczba_octave[number_attempts];
        int liczba_terce[number_attempts];

        if(diff_level==0)
        {
            for(int i = 0 ; i < number_attempts; i++)
            {
                int rand_octave =( rand() % 8 ) + 1;
                for( int j = 0 ; j <= rand_octave ; j++)
                {
                    liczba_octave[i]=octave[j+1];
                }
            }
        }

        else if(diff_level==1)
        {
            for(int i = 0 ; i < number_attempts; i++)
            {
                int rand_terce =( rand() % 22 ) + 1;
                for( int j = 0 ; j <= rand_terce ; j++)
                {
                    liczba_terce[i]=terce[j+1];
                }
            }
        }

        if(diff_level==0)
        {
            freq=liczba_octave[0];     
        }
        else if(diff_level==1)
        {
            freq=liczba_terce[0];      
        }
    }

    virtual void genere_freq()
    {
        Beep(freq,3000);           
    }
};

int main()
{
    srand( time( NULL ) );

    Test f1;

    f1.select_freq();                       

    for(int i = 0 ; i <= f1.number_attempts ; i++)  
    {
        f1[i];                                  //tutaj chcialbym przesuwac tablice o jedno miejsce w prawo, ale nie wiem jak skoro
                                                    //tablica jest typu int a obiekt jest obiektem
        cout<<"Czestotliwosc numer: "<<i<<endl;
        f1.genere_freq();                       
        Sleep(500);
    }

    system("pause");
    return 0;
}
 

Teraz tylko nie wiem jak zrobić ten jeden element :

for(int i = 0 ; i <= f1.number_attempts ; i++)  
    {
        f1[i];                                  //tutaj chcialbym przesuwac tablice o jedno miejsce w prawo, ale nie wiem jak skoro
                                                    //tablica jest typu int a obiekt jest obiektem
        cout<<"Czestotliwosc numer: "<<i<<endl;
        f1.genere_freq();                       
        Sleep(500);
    } 

Co mam namyśli? Jeżeli freq=liczba_octave[0]; lub freq=liczba_terce[0]; (czyli pierszwszemu elementowi, tylko teraz równa się jego wartości, dlatego kombinowałem ze wskaźnikami) to chciałbym móc w pętli w mainie zrobić w miejscu tego f1[i], linie która przesuwa się po wartościach tablicy w prawo, zależnie od jej wielkości, aż do number_attempts. Czyli np. freq=liczba_terce[0]; freq=liczba_terce[1]; freq=liczba_terce[2]; [...].

2
int liczba_octave[number_attempts];
int liczba_terce[number_attempts];

Te tablice istnieją tylko w funkcji select_freq(), poza nią nie istnieją. Jak chcesz mieć je w dowolnym momencie życia obiektu, to musisz je przenieść do klasy, tak jak zmienna freq. Na początku mogą być public, dzięki czemu będziesz miał dostęp do nich w ten sposób:

f1.liczba_terce[i]

aczkolwiek ładniejszym rozwiązaniem jest stworzenie funkcji, która operuje na nich, zamiast samemu w main.

BTW w C++ tablice nie mogą mieć zmiennego rozmiaru: number_attemps jest zmienną, więc nie może służyć jako rozmiar przy tworzeniu statycznej tablicy. Nawet jeśli się skompiluje, to tylko dlatego że pewne kompilatory mają takie rozszerzenie.

1

Poszedłem jednak trochę inną zważając na to co napisałeś powyżej, mam tylko jeden problem. Nie wiem dlaczego dostaje takie błędy:
undefined reference to Test::select_freq()'| undefined reference to Test::genere_freq()'|

Po zmianie obiektu na typ Freq, błędy się nie pojawiają ale dostaje jeszcze coś takiego:
undefined reference to `vtable for Test'|

Kod wygląda tak:

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <windows.h>

using namespace std;

class Test
{
public:
    int number_attempts;
    int diff_level;

    Test(int n_r=5, int d_l=0)
    {
        number_attempts=n_r;
        diff_level=d_l;
    }

    virtual void genere_freq();
    virtual void select_freq();
};
class Freq :public Test
{
public:
    int* liczba_octave;
    int* liczba_terce;

    Freq::Freq(int n_r=5, int d_l=0) :Test(n_r=5, d_l=0)
    {
        number_attempts=n_r;
        diff_level=d_l;
        liczba_octave = new int[n_r];
        liczba_terce = new int[n_r];
    }

    Freq::~Freq()
    {
    delete [] liczba_octave;
    delete [] liczba_terce;
    }

    virtual void select_freq()
    {
        double octave[8] =  {25, 250, 500, 1000, 2000, 4000, 8000, 16000};
        double terce[22] = {125, 160, 200, 250, 315, 400, 500, 630, 800, 1000, 1250, 1600, 2000, 2500, 3150, 4000, 5000, 6300, 8000, 10000, 12500, 16000};

        if(diff_level==0)
        {
            for(int i = 0 ; i < number_attempts; i++)
            {
                int rand_octave =( rand() % 8 ) + 1;
                for( int j = 0 ; j <= rand_octave ; j++)
                {
                    if(j==rand_octave)
                    liczba_octave[i]=octave[j];
                }
            }
        }

        else if(diff_level==1)
        {
            for(int i = 0 ; i < number_attempts; i++)
            {
                int rand_terce =( rand() % 22 ) + 1;
                for( int j = 0 ; j <= rand_terce ; j++)
                {
                    if(j==rand_terce)
                    liczba_terce[i]=terce[j];
                }
            }
        }
    }

    virtual void genere_freq()
    {
        if(diff_level==0)
        {
            Beep(*liczba_octave,3000);
        }
        else if(diff_level==1)
        {
            Beep(*liczba_terce,3000);
        }

    }
};

int main()
{
    srand( time( NULL ) );

    Test f1;

    f1.select_freq();

    for(int i = 0 ; i <= f1.number_attempts ; i++)
    {
        cout<<"Czestotliwosc numer: "<<i<<endl;
        f1.genere_freq();
        Sleep(500);
    }

    ~Freq();

    system("pause");
    return 0;
}
 
1
~Freq();

Prawie nigdy nie należy wywołać destruktora ręcznie, destruktor to coś co samo się wywoła. Istnieją przypadki, kiedy to się robi, ale to już bardzo zaawansowane zagadnienia, dla Ciebie na razie wystarczy słowo nigdy.
Poza tym co to za wywołanie, na jakim obiekcie to jest? To tak jakby wywołać select_freq() bez podania obiektu.

undefined reference to Test::select_freq()'
undefined reference to Test::genere_freq()'
Klasa Test nie implementuje przecież tych funkcji, a próbujesz je wywołać:

Test f1;
f1.select_freq();

Po zmianie obiektu na typ Freq, błędy się nie pojawiają ale dostaje jeszcze coś takiego:
undefined reference to vtable for "Test"
Skoro Test nie implementuje tamtych metod, to one powinny być czysto wirtualne:

virtual void genere_freq() = 0;
virtual void select_freq() = 0;

Test jest klasą bazową, więc zalecaną praktyką jest, żeby zdefiniować destruktor dla tej klasy jako wirtualny, nawet jeśli ma być pusty.

virtual ~Test() {}
//albo w C++11
virtual ~Test() = default;
Freq::~Freq()

Jak definiujesz w ciele klasy to Freq:: jest zbędne i niepożądane.

0

Już się kompiluje, teraz tylko mam z tym problem że generuje mi cały czas tę samą częstotliwość. Postaram się sam z tym uprać, jeżeli nie dam rady to wtedy zwrócę się o pomoc ponownie.

A jeżeli chodzi o to co napisałeś powyżej to:

virtual void genere_freq() = 0;
virtual void select_freq() = 0; 

Zapomniałem o tym.

 Test f1;
f1.select_freq();

Myślałem że dziedziczę również metody, no ale w końcu po to tutaj piszę, żeby się czegoś dowiedzieć :)

Czy jeżeli chcę przekazać wartość argumentu z maina do klasy to muszę użyć this ?
I tak klasa Test będzie rozbudowana dużo bardziej i to ona będzie operować klasą Freq, ale chciałbym żeby to jak na razie zadziałało w takiej postaci, bo łatwiej będzie mi to przebudować :)

1
staniuu napisał(a):

Myślałem że dziedziczę również metody, no ale w końcu po to tutaj piszę, żeby się czegoś dowiedzieć :)
Klasa pochodna dziedziczy po bazowej, w drugą stronę byłoby dosyć dziwne.

Czy jeżeli chcę przekazać wartość argumentu z maina do klasy to muszę użyć this ?
Co to znaczy przekazać do klasy? Nie wiem co masz na myśli, ale prawie na pewno odpowiedź brzmi nie, czym jest this w mainie?

I tak klasa Test będzie rozbudowana dużo bardziej i to ona będzie operować klasą Freq, ale chciałbym żeby to jak na razie zadziałało w takiej postaci, bo łatwiej będzie mi to przebudować :)
Ogólnie to Freq nie jest Testem, więc nie powinno publicznie dziedziczyć.

0

Jak chcę teraz project rozdzielić na pliki i pojawia mi się taki błąd w tej linijce:

Freq(int, int, int) :Test();
    ~Freq();
14|error: no matching function for call to `Test::Test() 
1

Bo 'Test' nie ma bezparametrowego konstruktora.

0

Ok. Już wszystko wiem. Dzięki twonek! Pozdrawiam.
Temat do zamknięcia :)

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