Forum » Programiranje » [c++] "Čudno" obnašanje virtualnih metod napram delphiju
[c++] "Čudno" obnašanje virtualnih metod napram delphiju
zhigatsey ::
Živjo,
Sem se že zelo razpisal vendar sem ponesreči vse zbrisal, tako da tole je malo skrajšana verzija....
Kot vidite, imam dva razreda TemplateFrame in TemplateMainFrame.... V prvem razredu v
njegovem konstruktorju, kličem metodo CreateControls(), ki mi ob kreiranju objekta tipa TemplateFrame,
kreira vse potrebne kontrole.... V izpeljanem razredu TemplateMainFrame pa bi rad kreiral še več
kontrol in sicer še main menu in status bar... Po mojem mišljenju bi moral v izpeljanem razredu samo
overridati metodo CreateControls(), v kateri bi dodal še kodo za kreiranje dodatnih kontrol....
Vendar pa se ob kreiranju objekta tipa TemplateMainFrame izvede samo metoda TemplateFrame::CreateControls(),
torej se Main menu in status bar ne kreirata... Za rešitev tega problema bi moral klicati metodo CreateControls še
v konstruktorju TemplateMainFrame ali kako... Samo to je ponvljanje kode in meni čista bedarija.... Bi moral
potem v vseh izpeljanih razredih klicati v konstruktorju še CreateControls()...
Sem se napačno lotil problema? Imate kakšen nasvet?
Hvala za odgovore?
Sem se že zelo razpisal vendar sem ponesreči vse zbrisal, tako da tole je malo skrajšana verzija....
Kot vidite, imam dva razreda TemplateFrame in TemplateMainFrame.... V prvem razredu v
njegovem konstruktorju, kličem metodo CreateControls(), ki mi ob kreiranju objekta tipa TemplateFrame,
kreira vse potrebne kontrole.... V izpeljanem razredu TemplateMainFrame pa bi rad kreiral še več
kontrol in sicer še main menu in status bar... Po mojem mišljenju bi moral v izpeljanem razredu samo
overridati metodo CreateControls(), v kateri bi dodal še kodo za kreiranje dodatnih kontrol....
Vendar pa se ob kreiranju objekta tipa TemplateMainFrame izvede samo metoda TemplateFrame::CreateControls(),
torej se Main menu in status bar ne kreirata... Za rešitev tega problema bi moral klicati metodo CreateControls še
v konstruktorju TemplateMainFrame ali kako... Samo to je ponvljanje kode in meni čista bedarija.... Bi moral
potem v vseh izpeljanih razredih klicati v konstruktorju še CreateControls()...
Sem se napačno lotil problema? Imate kakšen nasvet?
Hvala za odgovore?
#include <iostream> using namespace std; class TemplateFrame { public: TemplateFrame() { CreateControls(); } virtual void CreateControls() { cout << "TemplateFrame controls creation." << endl; } }; class TemplateMainFrame : public TemplateFrame { public: TemplateMainFrame() : TemplateFrame() {} void CreateMainMenu() { cout << "Main menu creation." << endl; } void CreateStatusBar() { cout << "Status bar creation." << endl; } virtual void CreateControls() { TemplateFrame::CreateControls(); CreateMainMenu(); CreateStatusBar(); } }; int main() { TemplateMainFrame* myFrame = new TemplateMainFrame(); delete myFrame; return 0; }
BlueRunner ::
V C++ se virtualnih metod nikoli ne kliče iz konstruktorja, zaradi same narave konstrukcije objekta. Obširno razlago najdeš tukaj. Na kratko pa moraš vedeti, da se konstruktorji implicitno kličejo ("TemplateMainFrame() : TemplateFrame() {}" je v tvojem primeru identično "TemplateMainFrame() {}", saj je konstrukcija starša implicitna) od najglobjega starša navzgor proti tipu razreda za instanco, ki jo ustvarjaš. Med drugim to v tvojem primeru pomeni, da Vtable v času izvajanja TemplateFrame::TemplateFrame vsebuje samo tiste metode, ki so bile definirane do tega razreda. Šele v konstruktorju TemplateMainFrame::TemplateMainFrame se v tabelo vpiše še implementacija iz razreda TemplateMainFrame. To pomeni, da noben konstruktor, ki je v vrsti pred tem konstruktorjem ne bo videl implementacije virtualnih metod iz tega razreda.
Če bi imel še tretji razred v vrsti (TemplateMainFrameEx : public TemplateMainFrame), potem bi njegove virtualne metode postale dosegljive šele v konstruktorju TemplateMainFrameEx::TemplateMainFrameEx. To sicer pomeni, da lahko v konstruktorju skoraj vedno (če bi imel pure virtual, potem bi vse skupaj odpovedalo) kličeš virtualno metodo, skoraj nikoli pa to ne bo imelo zaželenega rezultata.
Glede na to, da se gre tukaj za GUI komponente, lahko njihovo inicializacijo razdeliš na dva dela. V konstruktorju pripraviš vse spremenljivke in interno stanje, v metodi Create pa izvedeš dejansko kreacijo ročice za GUI objekt. S tako razdeljeno implementacijo, pa že v začetku implicitno ločiš dejanski razred (data) od njegove trenutne predstavitve (presentation), kar pa tudi ni slaba ideja. Ravno tako pa lahko ločiš logiko konstruktorjev, ki navadno propadejo zaradi terminalnih razlogov (npr. premalo pomnilnika) od logike prikaza podatkov, ki lahko propadejo tudi zaradi bolj banalnih razlogov (premalo pravic za stvaritev okna, X strežnik je nedosegljiv, preveč odprtih oken, ...), kar se lahko obvlada in o čemer se da uporabnika tudi obvestiti.
Če bi imel še tretji razred v vrsti (TemplateMainFrameEx : public TemplateMainFrame), potem bi njegove virtualne metode postale dosegljive šele v konstruktorju TemplateMainFrameEx::TemplateMainFrameEx. To sicer pomeni, da lahko v konstruktorju skoraj vedno (če bi imel pure virtual, potem bi vse skupaj odpovedalo) kličeš virtualno metodo, skoraj nikoli pa to ne bo imelo zaželenega rezultata.
Glede na to, da se gre tukaj za GUI komponente, lahko njihovo inicializacijo razdeliš na dva dela. V konstruktorju pripraviš vse spremenljivke in interno stanje, v metodi Create pa izvedeš dejansko kreacijo ročice za GUI objekt. S tako razdeljeno implementacijo, pa že v začetku implicitno ločiš dejanski razred (data) od njegove trenutne predstavitve (presentation), kar pa tudi ni slaba ideja. Ravno tako pa lahko ločiš logiko konstruktorjev, ki navadno propadejo zaradi terminalnih razlogov (npr. premalo pomnilnika) od logike prikaza podatkov, ki lahko propadejo tudi zaradi bolj banalnih razlogov (premalo pravic za stvaritev okna, X strežnik je nedosegljiv, preveč odprtih oken, ...), kar se lahko obvlada in o čemer se da uporabnika tudi obvestiti.
zhigatsey ::
// Ko sem tole pisal, še nisem videl BlueRunnerjevega posta..... ampak bom kar pustil
Upam da se razumemo kaj me muči...
Bom dal še en primer....
Recimo imam spet dva razreda TemplateFrame in TemplateMainFrame, ki je nasleden iz TemplateFrame....
V roditelju(TemplateFrame), lovim event ko uporabnik klikne križec, hoče zapreti okno in ko se
ta event zgodi kličem funkcijo OnQuit recimo... V tej funkciji imam kodo, ki mi postori še kakšen
task ob zaprtju... V nasledenem razredu TemplateMainFrame pa se izmislim da bi rad, ko zaprem
program, da me vpraša npr. ali resnično želim zapustiti program.... V delphiju sem samo
overridal funkcijo OnQuit() in dodal kodo za prikaz msg boxa, ki me je vprašal ali želim
zapustiti program in če sem kliknil yes sem samo poklical inherited (v cpp bi to naredil najbrž takole: TemplateFrame::OnQuit()) da se je izvedla še OnQuit funckcija roditelja.... Torej se najprej kliče funkcija najvišje nasledenega razreda in potem z inherited besedico,
izvajaš kodo roditeljev.... Pri cpp pa je zgleda ravno obratno, in se najprej kliče najnižja funkcija v hierarhiji....
Upam da se razumemo kaj me muči...
Bom dal še en primer....
Recimo imam spet dva razreda TemplateFrame in TemplateMainFrame, ki je nasleden iz TemplateFrame....
V roditelju(TemplateFrame), lovim event ko uporabnik klikne križec, hoče zapreti okno in ko se
ta event zgodi kličem funkcijo OnQuit recimo... V tej funkciji imam kodo, ki mi postori še kakšen
task ob zaprtju... V nasledenem razredu TemplateMainFrame pa se izmislim da bi rad, ko zaprem
program, da me vpraša npr. ali resnično želim zapustiti program.... V delphiju sem samo
overridal funkcijo OnQuit() in dodal kodo za prikaz msg boxa, ki me je vprašal ali želim
zapustiti program in če sem kliknil yes sem samo poklical inherited (v cpp bi to naredil najbrž takole: TemplateFrame::OnQuit()) da se je izvedla še OnQuit funckcija roditelja.... Torej se najprej kliče funkcija najvišje nasledenega razreda in potem z inherited besedico,
izvajaš kodo roditeljev.... Pri cpp pa je zgleda ravno obratno, in se najprej kliče najnižja funkcija v hierarhiji....
Zgodovina sprememb…
- spremenil: zhigatsey ()
Vesoljc ::
class ca { public: virtual void fa() { // do ca stuff } }; class cb: public ca { public: virtual void fa() { // eksplictino poklicemo base funkcijo ca::fa(); // also do cb stuff } };
tole mislis?
Abnormal behavior of abnormal brain makes me normal...
zhigatsey ::
Ja to mi je jasno, da lahko kličemo base funkcijo v otroku....
Kar sem na hitrco pregledal članek, ki ga je navedel BlueRunner je najbrž tole problem...
I'll begin with the recap: you shouldn't call virtual functions during construction or destruction, because the calls won't do what you think, and if they did, you'd still be unhappy. If you're a recovering Java or C# programmer, pay close attention to this Item, because this is a place where those languages zig, while C++ zags.
Bolj podrobno pa bom prebral doma...
Kar sem na hitrco pregledal članek, ki ga je navedel BlueRunner je najbrž tole problem...
I'll begin with the recap: you shouldn't call virtual functions during construction or destruction, because the calls won't do what you think, and if they did, you'd still be unhappy. If you're a recovering Java or C# programmer, pay close attention to this Item, because this is a place where those languages zig, while C++ zags.
Bolj podrobno pa bom prebral doma...
Vredno ogleda ...
Tema | Ogledi | Zadnje sporočilo | |
---|---|---|---|
Tema | Ogledi | Zadnje sporočilo | |
» | "Dinamicna" sprememba razreda v C++Oddelek: Programiranje | 1944 (1336) | Spura |
» | Java je OOP ??Oddelek: Programska oprema | 2319 (2022) | Voyager |
» | JAVA neujemanje tipovOddelek: Programiranje | 2002 (1635) | l0g1t3ch |
» | [c++] standardni c++ in dogodki(events)Oddelek: Programiranje | 1764 (1589) | yeti |
» | Front Page 2000-velikost oknaOddelek: Izdelava spletišč | 1109 (989) | Tody |