Sziasztok!
Írok egy progit, amiben azt vettem észre, hogy nagyon sok teljesen hasonló függvényt kellett írnom. Ezeken a hasonló függvényeken belül csak kis részletek térnek el. Nagyjából így néznek ki:
void fv1(...) {
// fájl beolvasás soronként
// a sor manipulálása 1
// kiírás új fájlba
}
void fv2(...) {
// fájl beolvasás soronként
// a sor manipulálása 2
// kiírás új fájlba
}
void fv3(...) {
// fájl beolvasás soronként
// a sor manipulálása 3
// kiírás új fájlba
}
// stb...
Nyilvánvaló, hogy sokkal jobb lenne, ha csak a manipulálás függvényeket írnám meg külön-külön, és a fv1(), fv2() ... fvX() helyett, csak egy fvGeneral() lenne, aminek az egyik paramétere egy manipulal() függvény lenne. És ezek után a függvények listája a következőképpen nézhetne ki:
void fvGeneral(..., FunctionType manipulal(...)) {
// fájl beolvasás soronként
outString = manipulal(...);
// "outString" kiírása új fájlba
}
std::string manipulal1(std::string in) {
std::string out;
// "in" string manipulációja
return out;
}
std::string manipulal2(std::string in) {
std::string out;
// "in" string manipulációja
return out;
}
std::string manipulal3(std::string in) {
std::string out;
// "in" string manipulációja
return out;
}
int main() {
// a fő program egyéb részei
fvGeneral(..., manipulal1());
fvGeneral(..., manipulal2());
fvGeneral(..., manipulal3());
}
Előre is köszönöm a segítséget!
- 2833 megtekintés
Hozzászólások
Nem tudom milyen manipulasokrol van szo, de igy elsore nem tunik memora ill. CPU hatekonynak a terv.
Nem egyszerubb fogni a jo oreg switch case -t ? Valahol ugy is kell ilyen a programba szerintem.
- A hozzászóláshoz be kell jelentkezni
Én is pont ezt akartam javasolni. Vagy a generális függvénybe kellene egy olyan szerkezet, ami egy paramétertől függően meghívja az egyedi függvényeket, vagy eleve csak egy függvényt kellene írni.
- A hozzászóláshoz be kell jelentkezni
Valami ilyesmire gondolsz?
void fvGeneral(..., int man) {
// fájl beolvasás soronként
switch (man) {
case 1:
outString = manipulal1();
break;
case 2:
outString = manipulal2();
break;
case 3:
outString = manipulal3();
break;
}
// "outString" kiírása új fájlba
}
Ez sem rossz! De nagyon érdekelne a függvény-paraméteres megoldás is!
- A hozzászóláshoz be kell jelentkezni
Én csak azt nem értem, hogy miután leírtad a megoldást mi a kérdés?
Az, hogy konkrétan milyen szintaxissal kell függvényt átadni paraméterként?
Így elsőre ezt adja ki a "c function pointer" keresőkifejezés: http://www.newty.de/fpt/intro.html
Amit írtál az a C-s megoldás, csak szintaktikailag helytelenül leírva, de a fenti link alapján tudod javítani.
Mivel azonban C++-ban dolgozol (std::string C-ben nincs ugye) szebb lenne ha objecktum orientált megoldást készítenél.
Amit csinálsz kísértetiesen hasonlít erre a tervezési mintára: http://en.wikipedia.org/wiki/Command_pattern#Example_.28C.2B.2B.29
Annyi különbséggel, hogy neked nem elég egy interfész, hanem kell egy absztrakt ősosztály, amiben az execute metódusban benne van a fájl nyitás és zárás és közötte egy absztrakt metódusnak a meghívása, amit minden leszármazott másképp implementál.
Szerk.: Ez a minta még inkább passzol arra amit csinálni akarsz: http://en.wikipedia.org/wiki/Template_method_pattern
- A hozzászóláshoz be kell jelentkezni
Nagyon köszönöm!
Ez az absztrakt ősosztály tetszik. Megpróbálom az alapján elkészíteni a megoldást.
- A hozzászóláshoz be kell jelentkezni
#include <stdio.h>
#include <stdlib.h>
char *manipulal1(char *data) {
printf("manipulal1\n");
}
char *manipulal2(char *data) {
printf("manipulal2\n");
}
char *manipulal3(char *data) {
printf("manipulal3\n");
}
void feldolgoz(char *filename, char *manipfv(char *)) {
printf("feldolgoz\n");
char *data, *out;
// open
// while ...
// data = gets(...)
out = manipfv(data);
// close
}
int main(int argc, char **args) {
feldolgoz("filename.txt", manipulal1);
feldolgoz("filename.txt", manipulal3);
feldolgoz("filename.txt", manipulal2);
}
- A hozzászóláshoz be kell jelentkezni
Kösz!
(Akkor ez a klasszikus C-beli megodás.)
- A hozzászóláshoz be kell jelentkezni
Igen. Csak arra vigyázz, hogy a char *-gal átadott paramétereket in-place módosítod, tehát a bemeneti változód is meg fog változni, ha szövegbe belemódosítasz valamivel. Ha ezt nem akarod, akkor strcpy-vel le kell másolnod, viszont ez meg a teljesítményt csökkenti.
- A hozzászóláshoz be kell jelentkezni
A "teljesítmény" az én esetemben nem kritikus tényező. Az hogy 2 másodperc alatt fut-e le a program vagy 3, nem számít. Kösz!
- A hozzászóláshoz be kell jelentkezni
Megoldás 1 (STL like):
class Manipulal1
{
public:
string operator() (const string& in)
{ //do it}
};
class Manipulal2
{
public:
string operator() (const string& in)
{ //do it}
};
...
template <class Func>
void fvGeneral(..., Func f)
{
// fájl beolvasás soronként
outString = f(inString);
// "outString" kiírása új fájlba
}
int main()
{
fvGeneral(..., Manipulal1());
}
Előny: gyorsabb lehet (jobb optimalizációs lehetősége van a fordítónak)
Hátrány: nagyobb kódméret.
Egyébként leginkább a C-s fv-mutatós megoldással rokon.
Megoldás 2 (OOP):
class General
{
public:
void doIt(...);
virtual ~General() {}
private:
virtual string manipulal(const string& in) =0;
}
void General::doIt(...)
{
// fájl beolvasás soronként
outString = manipulal(inString);
// "outString" kiírása új fájlba
}
class Manipulal1 : public General
{
virtual string manipulal(const string& in);
}
string Manipulal1::manipulal(const string& in)
{
//do it
}
...
int main()
{
Manipulal1 man;
man.doIt(...);
}
"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o
- A hozzászóláshoz be kell jelentkezni
Köszi a segítséget!
A második megoldásban egyetlen dolgot nem értek:
virtual string manipulal(const string& in) =0;
Az "=0" mit csinál ott a sor végén?
- A hozzászóláshoz be kell jelentkezni
Azt mondja meg, hogy az eredeti class-ban nem adod meg a fuggveny torzset, mert nem lenne ertelme. Igy persze az eredetit peldanyositani sem lehet.
Miutan orokoltetsz belole egy masik osztalyt, es felulirod az eredeti metodust, mar peldanyosithato.
C-ben amugy a korabban mutatott fuggvenypointerekkel csinaltak meg a konyvtari qsort-ot altalanosra. (ld. Xanco megoldasat)
----
I have a solaris box that does nothing.. its pretty good at it aswell. - besok, deviantart
honlapkészítés
- A hozzászóláshoz be kell jelentkezni
Már írom ezt az OOP-s verziót. Gondom is volt a virtuális függvénnyel, mert kihagytam belőle az "=0" -t. Bár a fordítás lezajlott, de mégis fura üzeneteket írt ki.
Kösz, még egyszer!
- A hozzászóláshoz be kell jelentkezni
Ez a 0 gyakorlatilag egy NULL erteknek felel meg, nem?
--
()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.
- A hozzászóláshoz be kell jelentkezni
Nem, több okból:
1. C++-ban nincs NULL :)
"#define NULL (void*)0" még lehetne, de többet árt, mint használ...
El kell felejteni. (C++0x-ben (köv. szabvány) lesz nullptr.)
2. Ez csak egy jelölés, annyit jelent, hogy nincs definiálva. Csak az "=0" elfogadott.
(C++0x-ben lesz még "= delete", illetve "= default" is...)
"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o
- A hozzászóláshoz be kell jelentkezni
Felcsigaztal: mi a gond a "#define NULL (void*)0" kifejezessel amugy? (oke, ez esetben nem hasznalhato, megertettem. De mi gond van vele meg?)
--
()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.
- A hozzászóláshoz be kell jelentkezni
Leginkább az, hogy ez:
#define NULL ((void*)0)
int main()
{
int* p1;
p1=NULL;
return 0;
}
ezt váltja ki a G++-ból:
test.cpp: In function `int main()':
test.cpp:6: error: invalid conversion from `void*' to `int*'
Ami egyébként a szabványos viselkedés.
Ha osztályokról van szó, szülőosztály A, leszármazott B, akkor teljesen logikus, hogy egy A* mutatónak adhatunk B* értéket, viszont fordítva nem.
Igaz, nincs ilyen viszony a void* és az int* között, de azért a void* valahogy általánosabb, mutathat bármire, ezért a típusbiztonság miatt logikus így.
Ezek szerint ezt kéne írni:
p1=static_cast<int*>(NULL);
Ezt ugye írja akinek két anyja van. :)
(A "p1=(int*)NULL" jellegű dolgok nem a C++ részei, C örökség, nem illik ezeket használni...)
Így tehát a 0, azon kívül, hogy egy integer, még implicite cast-olódik minden mutatótípusra is, és azt jelenti amit várunk, akkor is, ha azon az architektúrán a null mutató bitmintája nem csupa 0.
Tehát C++-ban szokták ezt:
#define NULL 0
Csak ezt meg ugye minek, illetve...
Ezek után minek a nullptr a c++0x-be?
#define NULL 0
void foo(char *); //1
void foo(int); //2
int main()
{
char* str="test";
char* p=0;
foo(str); //remek: 1 fut
foo(p); //meg mindig jo: 1 fut
foo(NULL); //biztos nem ezt akartad: 2 fut
foo(0); //most melyiket is akartad: 2 fut
}
"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o
- A hozzászóláshoz be kell jelentkezni
Oke, megertettem. Bar en minden szivfajdalom nelkul hasznaltam eddig a (int*) NULL alaku kifejezeseket, ezek szerint ennek hasznalata kerulendo. Kar, hogy a C++ nem definialja maganak felul a NULL erteket, ha mar ennyi gond van vele amugy is. A fordito ugyis tudja, mikor fordit C++ kodot, es mikor C-t.
--
()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.
- A hozzászóláshoz be kell jelentkezni