Caute,
mam takyto problem. Robim program ktory pracuje s databazou (firebird, ale to je jedno).
Vysledky sql selectov z databazy zobrazujem v gride. To je bez problemov. Problem je
ze treba updatovat a insertovat riadky do gridu a db. Riesenim je Vygenerovat formular
ktory bude obsahovat edit, memo pripadne inu komponentu. Po ich naplneni urobim insert alebo update do DB.
Ale kedze takychto sql prehladov je vela musim to urobit univerzalne...A teraz.. V DB mam pre kazdy
prehlad zapisane ake komponenty sa maju vygenerovat, v akom poradi a podobne. Vygenerovanie, zobrazenie
nieje problem. Problem nastava ako vsetky komponenty ktore mam vygenerovane zjednotit tak aby som s nimi
mohol v programe manipulovat. Riesenie moze byt taketo : vytvorim si pole void* ukazovatelov.
pr.: void *pole[10], pripadne ak su vsetky tie komponenty odvodene od jednej classy tak BaseClass *pole[10]...
potom mozem urobit pole[0] = new My_CEdit, pole[1] = My_CMemo, ....atd, dobre je ze mam ukazovatele na vygenerovane
komponenty. Robim to preto takto lebo komponenty My_CEdit a My_CMemo su moje odvodene classy a doplnim do nich
funkcie ktore budu vo vsetkych mojich odvodenych triedach rovnake, kvoly tomu aby som mohol v jednom cykle
prebehnut tieto vygenerovane komponenty a nastavit ich. Lenze aby som mohol prisupit k metodam jednotlivych
tried musim si pamatat ze pole[0] je My_CEdit a pole[1] je My_CMemo, a podla toho ich pretypovat, inak sa s nimi
neda pracovat. To nieje az taky problem, ale je hlupost aby som robil nieco taketo :
switch (typKomponenty)
{
case 1:
{
My_CEdit(pole[0])->NastavVlastnosti();
break;
}
case 2:
{
My_CMemo(pole[1])->NastavVlastnosti();
break;
}
}
,pretoze tych komponent moze byt x vela. Neda sa urobit napriklad nieco take ze do BaseClass->hint() priradim text
"My_CEdit" pripadne "My_CMemo" a potom pretypovat obsah tej textovej premennej na danu classu, aby
som mohol zbehnut funkciu NastavVlastnosti() v cykle pre kazdy prvok pola? Alebo je ine riesenie?
Prosim o radu...
Fórum › C / C++
Spracovavanie rôznych tried v jednom cykle
To Jura_: uz som nad tym premyslal, ale programujem to v QT kniznici, a vsetky tie komponenty su odvodene od QWidget,
ak by som chcel pouzit polymorfizmus, musel by som prerobit tridu QWidget a pridat tam tie svoje funkcie ako virtualne...ale
kvoly jednemu programu nebudem prerabat celu triedu ktoru vyuzivam aj inde. Respektive ak si mal na mysli daco ine porad pls..
To Jura_:Skor by ma zaujimalo ci sa neda napriklad do stringovej premennej ulozit nazov triedy danej komponenty a potom ked by som siel pracovat
napriklad s pole[0] tak by som ho pretypoval na zaklade toho co je ulozene v tej stringovej premennej. Nejako z nej vytiahol nazov tej triedy...
To bruenor:
napadlo ta uz nieco take ako
MojaAbstraktnaTrieda: public QWidget
{
// tu uz su zdedene vsetky veci z QWidget
MojaMetoda()=0;
// nadefinujes svoje metody ako cisto apstraktne
}
a veselo si pouzivas odkazy na MojaAbstraktnaTrieda
To bruenor:
Tak samozrejme, ze se to da udelat, ale neprijde mi to jako ciste reseni. Jinak jsem myslel to, co ti tu uz rozved PaLaDiN, ale trochu jinak. Nemusis nic predelavat, protoze C++, na rozdil od jinych jazyku, disponuje vicenasobnou dedicnosti. Takze namet na reseni by byl(pisu to z hlavy):
class IBruenor
{public:
virtual void Settings() = 0;
//...
};
class CEdit: public QWidget, public IBruenor
{public:
virtual ~CEdit();
virtual void Settings();
};
To PaLaDiN: Co se tyce zjisteni nazvu typu, tak v C++ se sice daji zjistit a to pomoci typeinfo, ale presto je nedoporucuju. Jako duvod uvadim fakt, ze na kazdem prekladaci to vrati neco jineho, jinak se to chova s pouzitim virtualnich metod,jinak s pointery, atd.
perfektne, predbezne co som skusal, tak pomocou viac nasobnej dedicnosti a vytvoreni abstraknej triedy to funguje.
class ClassSkuska : public QWidget
{
public:
virtual ~ClassSkuska() {};
virtual void Settings()=0;
};
class CLineEdit_Brow : public QLineEdit, public ClassSkuska
{
Q_OBJECT
public:
CLineEdit_Brow(QWidget* parent=0);
void Init();
virtual ~CLineEdit_Brow() {};
virtual void Settings() {QMessageBox::information(NULL, "Message", "Settings");};
};
a potom v programe :
ClassSkuska *prem[10];
prem[0] = new CLineEdit_Brow(this);
prem[0]->Settings();
davam to sem, keby nahodou mal niekto ten isty problem. Dik moc chalani, keby daco tak sem este napisem,
ale vyzera ze to ide bez problemov.
To Jura_:Ano, mas pravdu QLineEdit dedi od QWidget, a mam aj jeden problem, ale mozno nesuvisi s tymto. Deklaracie vyzeraju tak ako som
napisal v mojom poslednom prispevku. Zavolanie spolocnej funkcie :
prem[0]->Settings();
je super, funguje bez problemov. Problem nastane ak chcem zavolat
prem[0]->move(x,y);
kde move je funkcia QWidget. Neurobi sa nic, komponenta sa vygenruje na suradniciach 0,0 a tam aj po zavolani
fukcie move ostane.
mozno to suvisi nejako s parentom, ale myslim ze ho posielam spravne, nakolko keby ho neposielam spravne tak sa asi ani
komponenta na danom rodicoskom formulary nezobrazi...
takto vyzera constructor mojej odvodenej komponnety
CLineEdit_Brow::CLineEdit_Brow(QWidget *parent) : QLineEdit(parent)
{.
...
}
Ak nastavim poziciu vo vnutri fukncii prem[0]->Settings() {QLineEdit::move(x,y)} vsetko je ok...
No jo, o tom jsem psal vyse.Pravdepodobne se ti povedlo zdedit tridu QWidget 2x a to jednou v QLineEdit(s tim neudelas nic) a podruhev ClassSkuska. Pokud to chces omezit pouzij virtualni dedicnost, pak by to mohlo fungovat.
class ClassSkuska : public QWidget
{
public:
virtual ~ClassSkuska() {};
virtual void Settings()=0;
};
class CLineEdit_Brow : virtual public QLineEdit, virtual public ClassSkuska
{
Q_OBJECT
public:
CLineEdit_Brow(QWidget* parent=0);
void Init();
virtual ~CLineEdit_Brow() {};
virtual void Settings() {QMessageBox::information(NULL, "Message", "Settings");};
};
Popr. tohle(prijde mi to lepsi nez virtualni dedicnost)
class ClassSkuska// : public QWidget - zbytecne, trida ClassSkuska je jen interface - zadne definice
{
public:
virtual ~ClassSkuska() {};
virtual void Settings()=0;
};
class CLineEdit_Brow : public QLineEdit, public ClassSkuska
{
Q_OBJECT
public:
CLineEdit_Brow(QWidget* parent=0);
void Init();
virtual ~CLineEdit_Brow() {};
virtual void Settings() {QMessageBox::information(NULL, "Message", "Settings");};
};
To Jura_: Hmm vyskusal som virtualnu dedicnost, ale bez uspechu. Ten druhy priklad, nemozem pouzit...,
kvoly tomu ze vsetky vygenerovane komponenty potrebujem zdruzit do jedneho pola aby som s nimi robit v cykle..
teda napr : ClassSkuska *prem[10]
a potom
prem[0] = new CLineEdit_Brow(this) atd..
Kedze ClassSkuska je odvodena od QWidget tak ClassSkuska pozna funkcie QWidget, aj ich skutocne pozna, takze ide
urobit napriklad prem[0]->move(x,y), akurat ze to vobec nereaguje..., podobne je to aj pri ostatnych fukciach,
A to pole *prem[10] musi byt typu ClassSkuska, lebo tato trieda obsahuje tie moje nove virtualne fukcie.
Este ma tak napada ci nieje inde problem ze to nereaguje, mozno nejaky problem s parentom...idem sa na to este mrknut
Prosím, vkládejte kód jako
kod
a ne jako kod :)Tak jinak maly priklad(snad je to jednoduche):
#include <cstdlib>
#include <iostream>
#include <vector>
using namespace std;
class SomeClass
{public:
const char *str;
SomeClass(const char*s):str(s) {}
void Print() const {cout << str << endl;}
virtual ~SomeClass(){};
};
class IBruenor
{public:
virtual ~IBruenor(){};
virtual void DoSomething()const = 0;
};
class A: public SomeClass, public IBruenor
{public:
A(const char* str):SomeClass(str), IBruenor() {}
virtual ~A() {};
virtual void DoSomething()const { cout << "AAAAAaaaaaaaa" << endl;}
};
class B: public SomeClass, public IBruenor
{public:
B(const char* str):SomeClass(str), IBruenor() {}
virtual ~B() {};
virtual void DoSomething()const { cout << "BBBBbbbbbbbb" << endl;}
};
class CBruenorDemo:public std::vector<IBruenor*>
{
public:
CBruenorDemo(): std::vector<IBruenor*>() {}
~CBruenorDemo(){
for(iterator i=begin(); i!=end(); ++i) delete *i;
}
void Demo() const
{for(int i=0; i<size();++i){
(*this)[i]->DoSomething();
dynamic_cast<SomeClass*>((*this)[i])->Print(); // Musi se pretypovat na predka SomeClass, prottye IBruenor nezna metodu Print
}
}
};
int main(int argc, char *argv[])
{
CBruenorDemo c;
c.push_back(new A("A1"));
c.push_back(new B("B1"));
c.push_back(new A("A2"));
c.Demo();
system("PAUSE");
return EXIT_SUCCESS;
}
To bruenor:
Ouh, tak ted nevim, jestli jsem te nahodou nezmatnul. Protoze vector na funkcnost toho, co jsi chtel ty, nema absolutne zadny vliv. Vector jsem pouzil jen jako priklad pro ilustraci - misto pole(ma plno vyhod a ja jsem strasne liny).To nejdulezitejsi pro tebe je ten radek:
dynamic_cast<SomeClass*>((*this)[i])->Print();
Operator dynamic_cast zajisti pretypovani na predka. Krome toho, pokud se to nepovede, vyhodi vyjimku bad_cast nebo vrati NULLovy pointer.
To Jura_:Jj, nevadi ze nejde pristupovat k jednotlivym polozkam ako k polu, pole je sice pohodlnejsie, ale teraz to funguje tak ako ma,
cez dynamic_cast pristupujem k funkciam zakladnej triedy a tak isto mam pristup aj k fukciam tej mojej odvodenej triedy CLineEdit_brow.
Funguje to super. Dik moc este raz
To Jura_:
Predtym som to skusal este cez sablony tried, ale nedarilo sa mi prinutit vsetky nove komponenty aby som s nimi mohol pracovat ako s polom.
Nakoniec som uvazoval urobit nejaky zasobnik, alebo dynamicke pole do ktoreho by som vkladal vsetky komponenty, ale nevedel som to napisat univerzalne tak aby som k různym triedam pristupoval rovnako a nemusel si pamatat typ kazdej triedy a potom ju podla toho pretypovat aby som mohol pristupit k jej fukciam. Ale cez tieto vectory je to fajn riesenie.
bruenor píše:#
# To Jura_:Jj, nevadi ze nejde pristupovat k jednotlivym polozkam ako k polu, pole je sice pohodlnejsie, ale teraz to funguje tak ako ma,#
#cez dynamic_cast pristupujem k funkciam zakladnej triedy a tak isto mam pristup aj k fukciam tej mojej odvodenej triedy CLineEdit_brow.#
#Funguje to super. Dik moc este raz
Pristupovat k jednotlivym prvkum vectoru jde i pres operator []. Teda staci mit:
c.push_back(new A("A1"));
c.push_back(new B("B1"));
c.push_back(new A("A2"));
c[0]->DoSomething();
dynamic_cast<SomeClass*>(c[0])->Print();
A pokud bys chel zajistit chovani opeartoru[], tak bych misto dedicnosti pouzil kompozici(trida by nededila z vector, ale vector by byl atribut tridy).
To Jura: hmmm pekne, tak tym padom uz k tomu nemam co dodat :) Mam ale este jednu otazku, skusal som triedu, pouzijem tvoj priklad..
CBruenorDemo c; deklarovat dynamicky
CBruenorDemo *c = new CBruenorDemo;
ako vtedy pristupujes k jednotlivym polozkam?
c[0]->DoSomething(); mi hlasi : base operand '->' has non pointer type 'CBruenorDemo', ta z haluze som skusil
c[0].DoSomething(); a hlasi class 'CBruenorDemo' has no member named 'DoSomething()'
Inak k tomu fakt nemam viac co dodat, funguje to presne taka ko som chcel.
Cavte, ked som sa spatne vracal a prerabal trochu program, zasekol som sa pri jednej veci.
Triedu odvodenu od vectoru, co Jura_ napisal vyssie som doplnit o template
template <typename T>
class CBruenorDemo:public std::vector<IBruenor<T> *>
{
public:
CBruenorDemo(): std::vector<IBruenor<T> *>() {}
~CBruenorDemo()
{
for(iterator i=begin(); i!=end(); ++i) delete *i;
}
};
problem mam pri praci s iteratorom, kde prekladac hlasi chybu : missing template arguments before "i",
podla tej hlasky zrejme ocakava nejaky argument pre ten moj novy template. Prepisal som ho na tvar :
vector<IBruenor<T> *>::iterator i = begin(), ale neuspesne. Clanky na nete o iteratoroch mi moc nepomohli,
vie niekto ako na to?
Přidej příspěvek
Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku
×Vložení zdrojáku
×Vložení obrázku
×Vložení videa
Uživatelé prohlížející si toto vlákno
Podobná vlákna
Generovanie v cykle — založil XANI
čakanie v cykle na dokončenie handleru — založil yterbium
Najdlhšia postupnosť rôznych čísel — založil Jozef01
Vyvolavacia lista na vyber roznych moznosti — založil smsn
Win 32 GUI -styling rôznych vecí... — založil Mega.Lama
Moderátoři diskuze