Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

konstruktory a dziedziczenie

main88 16 Maj 2010 13:40 3937 23
  • #1 16 Maj 2010 13:40
    main88
    Poziom 12  

    Witam,
    zadeklarowałem klasę spółki z konstruktorem:

    Code:

    class spolki
    {
    public:
    float cena;
    float c_wk;
    CString name;
    int status;
    spolki(float,float,CString,int);
    };

    Konstruktor:
    Code:

    spolki::spolki(float a,float b,CString c,int d)
    {
    cena=a;
    c_wk=b;
    name=c;
    status=d;
    };

    Próbowałem dziedziczyć klasę "obserwowane" po klasie "spółki", po to by w razie potrzeby obiekty zawarte w spółki przeszły do klasy obserwowane(oczywiście zostając także i w obserwowanych). Kod:
    Code:

    class obserwowane : public spolki
    {
    public:
       obserwowane(float,float,CString,int);
    };

    Jego konstruktor w takiej postaci jak poniżej nie działa w pożądany przeze mnie sposób i kompliator(VC++) zwraca błąd o numerze C2512 czyli "no appropriate default constructor available". Czytałem w dokumentacji MSDN o tym błędzie, ale problemu nie zlikwidowałem. Dodatkowo nie wiem, czy to istotne, ale obiekty spółki trzymam w tablicy, w której elementy są definiowane przez konstruktor. Oto kod nie działającego konstruktora:
    Code:

    obserwowane::obserwowane(float f,float g,CString h,int j)
    {
    cena=f;
    c_wk=g;
    name=h;
    status=j;
    };

    0 23
  • #2 16 Maj 2010 14:32
    Dr.Vee
    VIP Zasłużony dla elektroda

    Konstruktor klasy pochodnej musi wywołać jeden z konstruktorów klasy podstawowej. Klasa spolki nie ma domylśnego konstruktora i to Ci próbuje przekazać kompilator :)

    Spróbuj tak:

    Code:
    obserwowane::obserwowane(float f, float g, CString h, int j)
    
        : spolki(f, g, h, j)
    {}

    0
  • #3 16 Maj 2010 14:51
    main88
    Poziom 12  

    Ok, pomogło.
    Ale pojawił się nowy problem, gdy próbowałem używać tych konstruktorów.
    Dokładniej, nie mogę zadeklarować tablicy obiektów tej klasy bez bezpośredniego użycia konstruktorów.

    Code:

    obserwowane tab[20];

    Pojawia się znowu błąd C2512, chciałbym by obiekt był tworzony po określonej akcji(odpowiedni przycisk). Przypuszczam, że powinienem uzyć polecenie funkcji wirtualnej(konstruktora wirtualnego?). Próbowałem dodać przed konstruktorem parametr virtual, ale nie pomogło. Nie wiem czy idę w dobrym kierunku.

    0
  • #4 18 Maj 2010 00:11
    Ballbreaker
    Poziom 11  

    Nie masz zdefiniowanego dla klasy konstruktora domyślnego wywoływanego bez parametrów:

    Code:
    obserwowane()


    Jak go zdefiniujesz, to problemy znikną.

    0
  • #5 18 Maj 2010 00:26
    main88
    Poziom 12  

    Doskonale o tym wiem, problem polega na tym, że zdeklarować muszę już na początku nie znając obiektów.
    Definicja natomiast ma następować po akcji naciśnięcia przycisku. Wyjaśniając jaki to ma wpływ na sens programu:
    Mam spółki zaliczone do klasy "spolki", po kliknieciu pewnego przycisku te obiekty mają powstać(także w tablicy) jako obiekty klasy "obserwowane". Inicjowane mają być więc konstruktorem, podejrzewam że chodzi tutaj o virtual.
    Chciałbym żeby ktoś zweryfikował możliwość użycia virtuala.
    Statycznie juz deklarowałem, wiem że będzie to działało.

    0
  • #6 18 Maj 2010 09:36
    Ballbreaker
    Poziom 11  

    Chodzi tu o to, że deklaracja tablicy obiektów, a więc zaalokowanie pamięci na te obiekty, jest jednocześnie ich utworzeniem. Ponieważ nie ma żadnych parametrów utworzenia każdego obiektu z osobna, każdy z nich zostanie utworzony za pomocą konstruktora domyślnego.

    Jeżeli chcesz żeby widać było globalnie tablicę, a stworzenie samych obiektów odkładasz na później, to zrób tablicę wskaźników do obiektu. Tablica będzie widoczna, a obiekty stwoorzysz swoim konstruktorem w swoim czasie.

    0
  • #7 20 Maj 2010 20:21
    main88
    Poziom 12  

    Wpadłem na lepszy pomysł i udoskonaliłem program nie deklarując osobnego konstruktora dla dziedziczącej klasy "obserwowane", tylko dziedziczyłem wszystko wraz z konstruktorem. Zrobiłem tak jak polecano mi post wyżej i zadeklarowałem tablicę wskaźników w sposób:

    Code:
    obserwowane *tab[13];

    Problem mam w momencie przypisywania do tej tablicy:
    Code:

    tab[li]=spolki(tablica[i].cena,tablica[i].c_wk,tablica[i].name,tablica[i].status);

    Nie wiem czy problemem nie jest też, że korzystam bądź co bądź z konstruktora przeznaczonego dla klasy wyższej czyli "spolki", ale głównym powodem, dla którego kompilator protestuje jest error C2679 o treści:
    Code:

    could be 'obserwowane &obserwowane::operator =(const obserwowane &)'

    Czy chodzi tutaj o zastosowanie referencji?

    0
  • #8 20 Maj 2010 20:26
    utak3r
    Poziom 25  

    main88 napisał:
    obserwowane *tab[13];


    Zaraz... tablica wskaźników do obiektów? A gdzie masz jakąś instrukcję new? Bo nie widzę... Zrób tablicę obiektów, zamiast wskaźników do obiektów :)

    A jeszcze lepiej, olej w ogóle tablicę i zró to tak, jak przystało na C++ - sugeruję szablon List albo Vector. Będziesz mógł wtedy posługiwać się wygodnymi iteratorami :)

    0
  • #9 20 Maj 2010 21:43
    main88
    Poziom 12  

    No właśnie tablicy do obiektów nie mogę zrobić, było o tym pare postów wyżej, polecano mi tablice wskaźników. A vector-ów chętnie się nauczę.
    Gdzie powinienem użyć operatora new? W definicji, przy wstawianiu elementów do tablicy?

    0
  • #10 20 Maj 2010 22:19
    utak3r
    Poziom 25  

    przed wstawieniem - bo niby co wstawiasz?....

    Code:

    TKlasa *nowy = new TKlasa();
    tab[i++] = nowy;


    teraz masz obiekt utworzony, a wskaźnik do niego zachowany w tablicy.

    1
  • #11 21 Maj 2010 04:36
    Ballbreaker
    Poziom 11  

    error C2679 dostajesz, bo nie masz zdefiniowanego konstruktora kopiującego.

    Jak tylko go stworzysz, dostaniesz błąd o niezgodności typów albowiem:

    Code:
    obserwowane *tab[13];
    deklarujesz tablicę wskaźników do obiektów, i masz do tego prawo, ale zaraz potem
    Code:
    tab[li]=spolki(tablica[i].cena,tablica[i].c_wk,tablica[i].name,tablica[i].status);
    robisz dziwną rzecz: tworzysz obiekt typu 'spolki', po czym usiłujesz go zapisać w tablicy wskaźników do obiektów klasy 'obserwowane'.

    Więc:
    1. Nie masz zdefiniowanego konstruktora kopiującego dla klasy spolki, ani dla klasy obserwowane, więc użycie operatora '=' jest w tym przypadku nielegalne.
    2. Jeśli już stworzysz taki operator w klasie spolki I w klasie obserwowane, to musisz zrobić rzutowanie w dół hierarhii dla spolki, aby przeksztalcic ją w obserwowane i przypisać do tablicy ( co samo w sobie jest dobrym pomysłem), ale:
    3. Masz tablicę wskaźników do obiektów obserwowane, a przypisujesz zamiast adresu konkretny obiekt klasy obserwowane (po uprzednim zrzutowaniu go z obiektu spolki, bo tylko tak to może się odbyć).

    Dlatego, lepiej zdefiniuj konstruktor domyślny wypełniony domyślnymi wartościami (zera i NULLe). I w sumie taka moja dygresja: jeśli nie wiesz jakie wartości domyślnie ma zawierać obiekt, to kompilator tego nie wyczaruje.


    POzdro.
    Owocnej pracy :)

    0
  • #12 28 Maj 2010 16:17
    main88
    Poziom 12  

    Rozwiązałem ten problem poprzez:

    Code:
    obserwowane *tab[13];

    konstruktor typu:
    Code:

    obserwowane::obserwowane(float f,float g,CString h, int j) : spolki(f,g,h,j)
    {}

    oraz
    Code:

    obserwowane *nowy=new obserwowane(tablica[i].cena,tablica[i].c_wk,tablica[i].name,tablica[i].status);   

    Odwołuje się do tego poprzez:
    Code:

    for(i=0;i<li;i++)
    disp.AddString(tab[i]->name);


    Jako, że program pisze od początku do końca napotykam od czasu do czasu na pewne problemy, nie chce zakładać nowego wątku bo to co zaraz opisze nie jest pewnie skomplikowanym zabiegiem. Zauważyłem, że funkcja w stylu:
    Code:

    int spolki::sprawdz(spolki s)
    {
       if(s.flaga==1)
          return 1;
       else if(s.flaga==0)
          return 0;
       else
          return 2;
    }

    mając zwrócić wartość inną niż 0, i wstawić tą wartość w pole kontrolne(u mnie EditControl) program znajduje błąd w stylu:
    "An unhandled win32 exception occured in stock_analyzer.exe[3460]".
    Myślę, że trzeba to jakoś omijać metodą try i catch. Może ktoś się o tym wypowiedzieć?

    0
  • #13 28 Maj 2010 19:47
    utak3r
    Poziom 25  

    Aby móc użyć przekazywania parametru przez wartość:

    Code:

    int spolki::sprawdz(spolki s)


    musisz mieć zdefiniowany konstruktor kopiujący. Jeśli go nie masz, pozostaje Ci przekazywanie parametru przez referencję:

    Code:

    int spolki::sprawdz(spolki *s)
    {
        if(s->flaga==1)
    ...............
    }

    0
  • #14 28 Maj 2010 20:23
    main88
    Poziom 12  

    Ok, udało się poprzez referencję. Napisze ten kod, bo być może ktoś kiedyś będzie śledził ten temat i będzie mu to pomocne.

    Code:


       int spolki::sprawdz(spolki &s)
    {
       if(s.flaga==1)
          return 1;
       else if(s.flaga==0)
          return 0;
    }

    0
  • #15 28 Maj 2010 21:19
    Dr.Vee
    VIP Zasłużony dla elektroda

    utak3r napisał:
    Aby móc użyć przekazywania parametru przez wartość:

    Code:

    int spolki::sprawdz(spolki s)


    musisz mieć zdefiniowany konstruktor kopiujący. Jeśli go nie masz, pozostaje Ci przekazywanie parametru przez referencję:


    Nie jest to prawda. Kompilator domyślnie generuje konstruktor kopiujący, o ile nie został zdefiniowany przez programistę.

    Pozdrawiam,
    Dr.Vee

    0
  • #16 29 Maj 2010 02:04
    utak3r
    Poziom 25  

    mmm, oczywiście masz rację, my bad... generowany jest niejawnie przez kompilator.

    0
  • #17 13 Lip 2010 10:28
    main88
    Poziom 12  

    Tym razem mam jakiś dziwny problem, co jakiś czas rozbudowuje ten program, wkleje teraz tylko wycinki kodu,
    dziedziczenie klas:

    Code:

    class obserwowane : public spolki
    {
    public:
       obserwowane(double,double,CString,int,int);
    };
    class trend : public spolki
    {
       public:
       trend(double,double,CString,int,int);
    };

    tutaj konstruktor:
    Code:

    spolki::spolki(double a,double b,CString c,int d,int e)
    {
    cena=a;
    c_wk=b;
    name=c;
    status=d;
    sektor=e;
    };

    Inicjowane jest w ten sposób:
    Code:

    spolki tablica[399]={

    spolki(4.76,2.31,"BANK BPH",0,1),
    spolki(45.23,1.21,"BOS",0,1)

    Nie bede wklejał całego inicjowania, bo tych spółek jest 399.
    Teraz identyczne kawałki dla dziedziczonych klas obserwowane i trend:
    Code:

    obserwowane::obserwowane(double f,double g,CString h, int j, int k) : spolki(f,g,h,j,k)
    {}
    obserwowane *tab[399];
    trend::trend(double l,double m,CString n, int o, int p) : spolki(l,m,n,o,p)
    {}
    trend *tab2[399];

    oraz niedziałające kawałki kodu w obsłudze przycisku(kompilator zwraca błędy):
    Code:

    if(obserw_b==1)
                      //1.warunek
                      if(tablica[i].sprawdz(tablica[i])!=1)
                      {
                      tablica[i].ustaw(tablica[i],1);
                      obserwowane *nowy=new obserwowane(tablica[i].cena,tablica[i].c_wk,tablica[i].name,tablica[i].status,tablica[i].sektor);   
                      tab[li]=nowy;
                      li++;
                      }
                      //2.warunek
                   if(trend_b==1)
                      if(tablica[i].sprawdz(tablica[i])!=2)
                      {
                      tablica[i].ustaw(tablica[i],2);
                      trend *nowy2=new trend(tablica[i].cena,tablica[i].c_wk,tablica[i].name,tablica[i].status,tablica[i].sektor);   
                      tab2[lg]=nowy2;
                      lg++;
                      }



    Zastanawiają mnie błędy, ponieważ są tam takie same czynności dla obu powstałych klas, wcześniej cały ten kod dla klasy obserwowane działał, a jak dodałem dla klasy trend, zaczął zwracać błędy:
    error C2065: 'nowy2' : undeclared identifier
    error C2061: syntax error : identifier 'trend'
    Nie wiem czy coś przeoczyłem, czy robię coś niedozwolonego.
    error C2065: 'nowy2' : undeclared identifier

    0
  • #18 14 Lip 2010 19:12
    main88
    Poziom 12  

    Mam nadzieję, że ktoś zajrzy w ten temat, bo już w ogóle nie mam pomysłów nawet co w programie sprawdzać.
    Szukając dziwnych rozwiązań, gdzie leży problem zastanawiałem się nawet czy nie ma innych procedur przy większej liczbie dziedziczeń.
    Myślałem też, że może powinienem wstawić wirtualny konstruktor.
    Jeśli ktoś byłby zainteresowany chciałbym wysłać ten program by ktoś bardziej doświadczony go przejrzał.

    0
  • #19 15 Lip 2010 01:08
    Daab
    Poziom 12  

    nowy2 jest wskaźnikiem na trend, ale w podanym fragmencie nie widać jego deklaracji. Mało tego - kompilator tez jej nie widzi więc coś jest na rzeczy

    error C2065: 'nowy2' : undeclared identifier

    po drugie "trend" jest za pewne jedną z twoich klas. Zwróć uwagę przy poprawnie wszystko po inkludowałeś do odpowiednich plików.

    0
  • #20 15 Lip 2010 07:40
    main88
    Poziom 12  

    Tak samo definiowałem wskaźnik do klasy obserwowane, co więcej próbowałem osobnym pliku visuala takiej metody dziedziczenia i przypisywania, czyli wskaźnik*=new element i nie trzeba było go deklarować, poza tym jeśli go zadeklaruje a później tylko przypisze to też wyskoczy błąd, oczywiście tylko dla klasy trend, sprawdzałem naprawdę wszystko, nic jest błędnie zrobione, nigdzie nie ma literówki żadnej, myślę, że to może być coś takiego, że w visualu wewnętrznie się zapisało w jakimś pliku i że trzeba teraz to ręcznie usunąć

    0
  • #21 15 Lip 2010 15:56
    Daab
    Poziom 12  

    Cytat:
    że w visualu wewnętrznie się zapisało w jakimś pliku i że trzeba teraz to ręcznie usunąć


    To co opisałeś faktycznie czasem się dzieje ale wtedy jest jedna prosta metoda na to: Rebuild Solution (skrót to chyba: ctrl+alt+F7 )

    Ogólnie to kompilatory korzystają z zasady minimalnej kompilacji, czyli kompilowane są jedynie te jednostki w których nastąpiły zmiany. Rebuilt Solution wymusza ponowną kompilację wszystkich jednostek. Jeśli to nie pomoże to błąd raczej jest gdzieś w kodzie.

    0
  • #22 15 Lip 2010 15:58
    main88
    Poziom 12  

    Takim sposobem praktycznie zawsze kompiluje, szczerze mówiąc już wszystko sprawdzałem i straciłem nadzieję, że można tam coś zrobić. Program powinien działać, gdyż kawałki jego kodu działają, wszystko jest ok a mimo to on się nie kompiluje. Problem na pewno nie jest prosty i jeśli ktoś miałby czas to mógłbym program wysłać, aby ktoś się nad nim lepiej zastanowił.

    0
  • #23 18 Lip 2010 23:44
    Dr.Vee
    VIP Zasłużony dla elektroda

    Tak to jest, jak się stosuje "dziedziczenie przez schowek", czyli copy-paste.

    Przejrzyj kod/deklarację klasy trend - czy w każdym miejscu zmieniłeś nazwę klasy z obserwowany na trend? Czy dołączasz odpowiedni nagłówek? Czy zabezpieczenie przed podwójnym dołączeniem nie używa tego samego #define?

    Pozdrawiam,
    Dr.Vee

    0
  • #24 08 Kwi 2011 16:24
    main88
    Poziom 12  

    przebudowałem wszystkie pliki, usunąłem co nie było niezbędne i program już dobrze śmiga

    0