abcd423417984 Skrevet 1. oktober 2003 Del Skrevet 1. oktober 2003 C/C++ Kodesnutter Inspirert av PHP forumet ønsker jeg nå å starte en tråd hvor brukere kan legge igjen små nyttige kodesnutter andre kanskje kan få bruk for. Reglene for tråden er enkle; ingen diskusjon, bare pasting av kode med evt kommentarer til hva som ble pasta. Ønsker du/dere å diskutere noe fra tråden anbefaler jeg å lage en tråd dedikert til dette. Si ifra hvis dette blir gjort så skal jeg legge igjen en link her. Innholdsfortegnelse invstring - Funksjoner for behandling av strenger Sortering av strenger - med norske regler. HUSK! Ikke ta æren for koden du finner her. Hvis du bruker koden i et prosjekt vær vennelig å gi opphavsmann credits, hvis ikke annet er nevnt. Lenke til kommentar
abcd423417984 Skrevet 1. oktober 2003 Forfatter Del Skrevet 1. oktober 2003 invstring En kompis hadde litt trøbbel med å gå over til C++ pga forskjellene i string funksjonene fra tidligere språk. Jeg lagde derfor en liten header fil som baserer seg på c++ string (std::string) som kan minne om enkelte funksjoner fra andre programmeringsspråk. Det er flere personer som har satt veldig pris på denne koden tidligere så jeg tenkte det var på tide å la andre få se den. Skal virke med visual studio.NET, visual studio .NET 2003, dev-c++, og gcc (g++). Hvordan bruke: lagre filen som invstring.h i samme folder som prosjektet ditt og bruk følgende i cpp kode filen: #include "invstring.h" for å bruke koden utover dette må du/dere se på funksjonsnavnene. Enten returnerer de en string eller så returnerer de en int. Eksempler: Mid() returnerer en del av stringen basert på posisjon (fra venstre) og størrelse. Mid2() returnerer en del av stringen basert på posisjonen (fra venstre) og en annen posisjon (fra venstre) Len() returnerer antall tegn i stringen Split() returnerer ord nr X (valgfri separator) fra en string LCase() returnerer hele stringen i lower case (små bokstaver) UCase() returnerer hele stringen i upper case (store bokstaver) UCaseFirst() returnerer stringen i lowercase med kun første bokstav i uppercase Left() returnerer X antall tegn fra venstre i stringen Right() returnerer X antall tegn fra høyre i stringen WordCount() returnerer antall ord i stringen (valgfri separator) GetFrom() returnerer hele stringen ETTER ord nr X (valgfri separator) Replace() returnerer stringen hvor substring X er byttet ut med substring Y (valgfritt om man vil ha det case sensitivt) InStr() returnerer posisjonen til en gitt substring i stringen (første instans) Reverse() returnerer det bakvendte av stringen (ABC blir CBA) ChopRight() returnerer stringen men har fjernet tegnet lengst til høyre ChopLeft() returnerer stringen men har fjernet tegnet lengst til venstre ChompRight() returnerer stringen men har fjernet tegnet lengst til høyre hvis dette er linjeskift ChompLeft() returnerer stringen men har fjernet tegnet lengst til venstre hvis dette er linjeskift StringCount() returnerer antall ganger en substring forekommer i stringen CharCount() returnerer antall ganger et tegn forekommer i stringen Koden har også en klasse som heter stringlist. Dette er rett og slett en samling av stringer (så man slipper å definere antall stringer på forhånd slik som på en array). her kan man legge til/fjerne/redigere osv ved hjelp av enkle klasse-funksjoner. Koden har også et par funksjoner som er rett og slett basert på denne klassen. Explode() tar en string og deler opp i mange ord etter valgfri separator. Så returnerer den en stringlist med hele innholdet. Implode() tar en stringlist og gjør om til en string med flere ord (valgfri separator) Koden har også en kode som ikke er testet ut fullt enda. Dette er følgende funksjoner: StrOpen() returnerer innholdet i en tekstfil som string StrSave() lagrer en string til en fil ps. krever ikke at du inkluderer <string> ettersom dette alt blir gjort i invstring.h Koden: Grunnet nesten 500 linjer med kode valgte jeg å legge den ut på pastebin.org. Den kan hentes på følgende adresse: http://www.pastebin.org/index.php?page=sho...&key=y0u4trem1x Hvis du/dere finner noen bugs ta kontakt Lenke til kommentar
kjetil7 Skrevet 2. oktober 2003 Del Skrevet 2. oktober 2003 Sortering av strenger Mange lurer på hvordan du sorterer strenger med norske regler (aa etter z osv.) Her er en enkel sak som bruker std::locale som et funksjonsobjekt til å sortere en std::vector bestående av strenger. #include <string> #include <locale> #include <vector> #include <algorithm> int main(int argc, char *argv[]) { // vi bruker en vector med strenger std::vector<std::string> v; // legger til strenger i vectoren v.push_back("Aabel, Per"); v.push_back("Zappa, Frank"); v.push_back("Young, Neil"); v.push_back("A Perfect Circle"); v.push_back("Mazzy Star"); v.push_back("Harvey, PJ"); v.push_back("Portishead"); v.push_back("Aaliyah"); v.push_back("Amos, Tori"); v.push_back("Aarset, Eivind"); v.push_back("Tool"); // bruker std::sort i algorithm for å sortere std::sort(v.begin(), v.end(), std::locale("") ); } Merk at std::locale c'toren vi bruker tar en streng som argument. Det er forskjell på å skrive std::locale() og std::locale("")! Den første varianten bruker "C" locale, mens den andre velger brukerens ønskede locale (i Windows vil det som regel si brukerens regioninstilling). Fordelen med dette er at koden også vil fungere for brukere med andre regioninstillinger (f.eks. svensker, tyskere....). Hvis du ønsker å hardkode strengen til å bruke norske regler, kan du prøve å skrive inn "no" istedenfor en blank streng, slik: std::sort(v.begin(), v.end(), std::locale("no") ); locale strengene er forøvrig ikke spesifisert i C++ standarden og kan være implementasjonsavhengig. Men jeg vil tro at "no" vil fungere de fleste steder Lenke til kommentar
søppel Skrevet 25. mai 2004 Del Skrevet 25. mai 2004 (endret) "To inline or not-to-inline" Hva med å la bruken av inline være opp til den som bruker funksjonene/headerene/biblioteket? /// a.cpp /// #include <iostream> #define M_use_inline #include "b.hpp" using namespace std; int main() { b(); b(); b(); return(0); } // main() /// b.hpp /// #ifndef _B_ #define _B_ void b(); #undef M_inline #if defined(M_use_inline) #undef M_use_inline #define M_inline inline #include "b.cpp" #else #define M_inline #endif #endif // #define _B_ /// b.cpp /// #include "b.hpp" #include <iostream> M_inline void b() { std::cout << "b()" << std::endl; } Edit: En liten detalj jeg surret litt med her er at GCC (MinGW også regner jeg med) må ha optimalisering påslått for å generere inline-kode. Endret 10. januar 2005 av søppel Lenke til kommentar
søppel Skrevet 30. mai 2004 Del Skrevet 30. mai 2004 (endret) Polymorfiske templates For litt mer viderekommende denne posten - så rett på sak; hvis vi starter med: #include <iostream> #include <time.h> #define M_iterations 100000000 unsigned long check; class A { public: char const* type2() const { return("A"); } }; // A class B : public A { public: char const* type2() const { return("B"); } }; // B class C : public B { public: char const* type2() const { return("C"); } }; // C class D : public C { public: char const* type2() const { return("D"); } }; // D A a; B b; C c; D d; int main() { std::cout << a.type2() << std::endl; std::cout << b.type2() << std::endl; std::cout << c.type2() << std::endl; std::cout << d.type2() << std::endl; } // main ..gir den følgende utskrift under kjøring: AB C D Ganske rett frem dette. Vanlig polyformi Si nå at vi vil flytte koden som skriver ut informasjon om type til en egen funksjon printType1. Siden alle objektene her har A som base-type kan vi bruke polyformi. Dette gjør at vi kan ha én printType1-funksjon som fungerer for alle objektene i hierakiet vårt. Vi legger derfor til en ny funksjon i klassene våre kallt type1 siden det må visse endringer (virtual) av hvordan en funksjon er deklarert for at polyformi skal tré inn, og siden vi skal bruke type2 til noe annet siden: class A { public: virtual const char* type1() const { return("A"); } ... }; // A class B { public: const char* type1() const { return("B"); } ... }; // B class C { public: const char* type1() const { return("C"); } ... }; // C class D { public: const char* type1() const { return("D"); } ... }; // D Legge merke til virtual-keywordet forran deklarasjonen av type1 i klassen A. Videre: void printType1(A const& obj) { std::cout << obj.type() << std::endl; } // printType1 int main() { printType1(a); printType1(b); printType1(c); printType1(d); return(0) } // main Dette gir følgende utskrift: AB C D Det som skjer her kalles polyformi. Hvis du ikke hadde lagt til virtual-keywordet hadde du fått følgende utskrift: AA A A Altså polyformi hadde ikke fungert. Det hele går ut på å "ikke vite". printType1 vet ikke hvilke objekter den får, men ved hjelp av polyformi blir riktig funksjon kallt alikevell. printType1 vet alikevell litt; den vet at objektet er en sub-type av A. Hvis vi tar dette med å "ikke vite" til et mer ekstremt nivå, havner vi borti det som kalles generics eller generisk programmering og templates i C++. Templates og generisk programmering Generisk programmering handler om å "ikke vite". Altså det handler om kode der ikke alt er spesifisert før noen velger å bruke koden. Tenk deg en klasse som skal fungere som en wrapper rundt C-arrayer. Denne klassen bør kunne lagre forskjellige ting eller typer. Uten templates kunne koden kanskje sett slik ut: class IntArray { public: IntArray(unsigned int size) { _array = new int[size]; } // constructor // Lot's of code here for all our functionality. private: int* _array; }; // IntArray class DoubleArray { public: DoubleArray(unsigned int size) { _array = new double[size]; } // constructor // Lot's of code here for all our functionality. private: double* _array; }; // DoubleArray ..og slikt kunne det fortsatt for hver eneste type vi vil lagre. Upraktisk. Med templates blir løsningen enkel: template<typename T> class Array { public: Array(unsigned int size) { _array = new T[size]; } // constructor // Lot's of code here for all our functionality. private: T* _array; }; // Array Array<int> my_int_array(100); // Et array med 100 int-elementer i. Array<double> my_double_array(100); // Et array med 100 double-elementer i. Vi kan også bruke egendefinerte typer: class UserType { }; Array<UserType> my_user_type_array(100); Polymorfiske templates Ok .. så kommer vi til det denne posten egentlig skal handle om: template<typename T> void printType2(T const& obj) { std::cout << obj.type2() << std::endl; } // printType2 int main() { ... printType2(a); printType2(b); printType2(c); printType2(d); ... return(0); } // main Forskjellen på printType1 og printType2 er at printType2 vet ennå mindre om parameteren sin enn det printType1 gjør. Dette gjør blandt annet at objekter som blir sendt inn til printType2 ikke lenger er nødt til å være en subtype av A: ... class OtherType { public: char const* type2() const { return("OtherType"); } }; // OtherType int main() { ... printType2(other); ... } // main Vi trenger heller ikke ha virtual forran type-funksjonen vår. Fordelene er blandt annet hastighet: class A { public: ... virtual void speedTest1() const { check = check + 1; }; void speedTest2() const { check = check + 1; }; ... }; // A class B { public: ... void speedTest1() const { check = check + 2; }; void speedTest2() const { check = check + 2; }; ... }; // B class C { public: ... void speedTest1() const { check = check + 3; }; void speedTest2() const { check = check + 3; }; ... }; // C class D { public: ... void speedTest1() const { check = check + 4; }; void speedTest2() const { check = check + 4; }; ... }; // D ... void doTest1(A const& obj) { obj.speedTest1(); } // doTest1 template<typename T> void doTest2(T const& obj) { obj.speedTest2(); } // doTest2 void speedTest1() { for(unsigned long i = 0; i < M_iterations; i++) { doTest1(a); doTest1(b); doTest1(c); doTest1(d); } } // speedTest1 void speedTest2() { for(unsigned long i = 0; i < M_iterations; i++) { doTest2(a); doTest2(b); doTest2(c); doTest2(d); } } // speedTest2 int main() { clock_t s; check = 0; s = clock(); speedTest1(); std::cout << "CPU time used: " << clock() - s << std::endl; std::cout << "(check is: " << check << ')' << std::endl; check = 0; s = clock(); speedTest2(); std::cout << "CPU time used: " << clock() - s << std::endl; std::cout << "(check is: " << check << ')' << std::endl; ... Under kjøring gir dette følgende utskrift: ...CPU time used: 5990000 (check is: 1000000000) CPU time used: 1380000 (check is: 1000000000) ... En hastighetsforskjell på ca. 400% med andre ord. En annen fordel er at vi får statisk typesjekking: ... template<typename T> class Handler; template<> class Handler<A> { public: Handler(A& o) :_o(o) { } // constructor template<typename T> void poly() { std::cout << "Handler<A>::poly<T>: " << static_cast<T&>(_o).type2() << std::endl; } // poly private: A& _o; }; // Handler<A> template<> class Handler<B> { public: Handler(B& o) :_o(o) { } // constructor template<typename T> void poly() { std::cout << "Handler<B>::poly<T>: " << static_cast<T&>(_o).type2() << std::endl; } // poly private: B& _o; }; // Handler<B> template<> class Handler<C> { public: Handler(C& o) :_o(o) { } // constructor template<typename T> void poly() { std::cout << "Handler<C>::poly<T>: " << static_cast<T&>(_o).type2() << std::endl; } // poly private: C& _o; }; // Handler<C> template<> class Handler<D> { public: Handler(D& o) :_o(o) { } // constructor template<typename T> void poly() { std::cout << "Handler<D>::poly<T>: " << static_cast<T&>(_o).type2() << std::endl; } // poly private: D& _o; }; // Handler<D> int main() { ... Handler<A> ha1(a); Handler<A> ha2(b); Handler<A> ha3(c); Handler<A> ha4(d); ha1.poly<A>(); ha2.poly<B>(); ha3.poly<C>(); ha4.poly<D>(); std::cout << std::endl; //Handler<B> hb1(a); // Compile time error :) Handler<B> hb2(b); Handler<B> hb3(c); Handler<B> hb4(d); hb2.poly<B>(); hb3.poly<C>(); hb4.poly<D>(); std::cout << std::endl; //Handler<C> hc1(a); // Compile time error :) //Handler<C> hc2(b); // Compile time error :) Handler<C> hc3(c); Handler<C> hc4(d); hc3.poly<C>(); hc4.poly<D>(); std::cout << std::endl; //Handler<D> hd1(a); // Compile time error :) //Handler<D> hd2(b); // Compile time error :) //Handler<D> hd3(c); // Compile time error :) Handler<D> hd4(d); hd4.poly<D>(); ... } // main Vi kan med andre ord ungå bruk av "fæle" ting som f.eks. dynamic_cast @ run-time. Så ting går igjen fortere og er sikkrere. Den komplette kildekoden finner du her: http://nostdal.net/paste/1b02679095a25ee2c...35a2414869.html Kom gjerne med kommentarer. :] Endret 1. juni 2004 av søppel Lenke til kommentar
søppel Skrevet 1. juni 2004 Del Skrevet 1. juni 2004 Function-pointers og Pointer-to-member(functions) Fort å glømme syntaxen på dette. #include <iostream> using namespace std; void test() { cout << "test()" << endl; } // test() class A { public: A() { i = 12345; } void test() { cout << "A::test()" << endl; } // test() void test2() { cout << "A::test2()" << endl; } // test2() int i; }; // class A int main() { A a; A* b = new A; void (*pf)(); // Pointer to function, 'pf' is the variable name. pf = test; pf(); void (A::*pm)(); // Pointer to member-function, 'pm' is the variable name. pm = &A::test; (a.*pm)(); (b->*pm)(); pm = &A::test2; (a.*pm)(); (b->*pm)(); int A::*pv; // Pointer to member-variable, 'pv' is the variable name (in this scope). pv = &A::i; cout << a.*pv << endl; return(0); } // main() http://www.function-pointer.org/ Lenke til kommentar
søppel Skrevet 1. juni 2004 Del Skrevet 1. juni 2004 POSIX Threads (pthread) og C++ (klasser) #include <iostream> #include <pthread.h> using namespace std; void* callback(void* obj); class Thread { public: int main() { cout << "Hi there" << endl; return(0); } void run() { pthread_create(&thread, 0, &callback, this); } pthread_t thread; }; // class Thread void* callback(void* obj) { static_cast<Thread*>(obj)->main(); return(0); } // callback int main() { Thread thread; thread.run(); return(0); } // main() Husk at du må linke med pthread-biblioteket, ellers får du SIGSEGV-feil. g++ -l pthread my_program.cpp -o my_program Lenke til kommentar
søppel Skrevet 1. juni 2004 Del Skrevet 1. juni 2004 (endret) Brukerdefinerte argumenter til standard-konstruktøren, i sammenheng med arrayer Si du har følgende: #include <iostream> class Element { public: Element(int value_ = 0) :_value(value_) { } // constructor operator int() { return(_value); } private: int _value; }; // Element int main() { using namespace std; Element arr[10]; // den defaulte konstruktøren blir altid kallt for(int i = 0; i < 10; i++) cout << arr[i] << endl; return(0); } // main Dette gir deg 10 elementer der alle har verdien 0. Hva om du ville at verdien skulle vært satt til noe annet under konstruksjon i sammenheng med arrayer? Enkel løsning: #include <iostream> class Element { public: static int default_value; Element(int value_ = default_value) :_value(value_) { } // constructor operator int() { return(_value); } private: int _value; }; // Element int Element::default_value; int main() { using namespace std; Element::default_value = 123; Element arr[10]; for(int i = 0; i < 10; i++) cout << arr[i] << endl; return(0); } // main En annen løsning: #include <iostream> typedef int (*Func)(); class Element { public: static Func defaultValue; Element() { _value = defaultValue(); } Element(int value_) :_value(value_) { } // constructor operator int() { return(_value); } // operator int private: int _value; }; // Element int defValue() { return(0); } // defValue Func Element::defaultValue = defValue; int incValue() { static int i = 0; return(i++); } // incValue int main() { using namespace std; Element::defaultValue = incValue; Element arr[10]; for(int i = 0; i < 10; i++) cout << arr[i] << endl; return(0); } // main Man kan fortsette slik og generalisere det hele ennå mer om man har lyst. Edit: Grunnen til at jeg har to konstruktører i det siste eksempelet: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=15759 Endret 3. juni 2004 av søppel Lenke til kommentar
søppel Skrevet 1. juni 2004 Del Skrevet 1. juni 2004 (endret) Arrayer med objekter som er subtyper (pass-på!) Dette gjelder når man sender disse arrayene til funksjoner: #include <iostream> class A { public: int a; }; // A class B : public A { public: int b; }; // B void f1(A* x) { x[1].a = 0; } // f1 template<typename T> void f2(T* x) { x[1].a = 0; } // f2 int main() { B b[10]; b[0].b = 1; std::cout << b[0].b << std::endl; f1(b); std::cout << b[0].b << " ...???" << std::endl; b[0].b = 1; f2(b); std::cout << b[0].b << std::endl; return(0); } // main ..ikke helt bra. Generellt sett er det ikke så lurt å ha en funksjon som tar i mot arrayer med objekter som egentlig kan være en subtype av typen spesifisert i parameterlista til funksjonen. Endret 1. juni 2004 av søppel Lenke til kommentar
søppel Skrevet 2. juni 2004 Del Skrevet 2. juni 2004 (endret) Threads under Win32 #include <iostream> #include <windows.h> using namespace std; DWORD WINAPI myThread(void* param) { while(1) { cout << "myThread()" << endl; Sleep(1000); } } // myThread int main() { CreateThread(0, 0, myThread, 0, 0, 0); while(1) { cout << "main()" << endl; Sleep(2000); } return(0); } // main http://msdn.microsoft.com/library/default....reatethread.asp Edit: Her er en som er mer C++'ish: #include <iostream> #include <windows.h> using namespace std; class Thread { public: /// Execute thread. void Thread::run() { CreateThread(0, 0, &_callback, this, 0, 0); } // run virtual char main() = 0; ///< Entrypoint for thread, defined by a subclass. private: friend DWORD WINAPI _callback(LPVOID obj) { static_cast<Thread*>(obj)->main(); return(0); } // callback }; // Thread class MyThread : public Thread { public: char main() { while(1) { cout << "MyThread::main() is alive!" << endl; Sleep(2000); } return(0); } // main }; // MyThread int main() { MyThread my_thread; my_thread.run(); while(1) { cout << "main() is alive!" << endl; Sleep(1000); } return(0); } // main Endret 21. august 2004 av søppel Lenke til kommentar
søppel Skrevet 6. juni 2004 Del Skrevet 6. juni 2004 (endret) En liten Makefile Edit: Det kan være en idé å titte på SCons, som er mye-mye bedre og lettere enn Make! Dere som kjører Windows må sansynligvis ha MSYS installert for at dette skal fungere. a.cpp #include <iostream> #include "a.hpp" using namespace std; int main() { A a; cout << a.value << endl; return(0); } a.hpp #ifndef _A_ #define _A_ #include "b.hpp" typedef B A; #endif b.hpp #ifndef _B_ #define _B_ struct B { int value; }; void funk(); #endif b.cpp #include "b.hpp" #include <iostream> void funk() { std::cout << "funk()" << std::endl; } Makefile # Preprocessor: CPP := cpp # Compiler: CC := g++ # Linker: LD := g++ # How to delete files: RM := rm -f # Extensions of source-files: EXT := .cpp # Extension of executable files: EXE_EXT := SOURCES := a b TARGET := program ## GENERATION OF DEPENDENCIES ## %.d: %$(EXT) @echo "*** Generating dependencies for $< ***" @set -e; \ $(RM) $@; \ $(CPP) $(CPPFLAGS) -MM -MT $(@:.d=.o) $< | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' > $@ ## LINKING ## %$(EXE_EXT): @echo "*** Linking $(@) ***" $(LD) $(SOURCES:=.o) $(LDFLAGS) -o $(TARGET) ## COMPILATION ## %.o: %$(EXT) @echo "*** Compiling $(@:.o=$(EXT)) ***" $(CC) -c $(@:.o=$(EXT)) $(TARGET): $(SOURCES:=.o) -include $(SOURCES:=.d) clean: $(RM) $(TARGET) $(SOURCES:=.o) mrproper: clean $(RM) $(SOURCES:=.d) make Vi kjører make: $ make*** Generating dependencies for b.cpp *** *** Generating dependencies for a.cpp *** *** Compiling a.cpp *** g++ -c a.cpp *** Compiling b.cpp *** g++ -c b.cpp *** Linking program *** g++ a.o b.o -o program ..så kan vi sjekke om dependency-systemet fungerer: $ makemake: `program' is up to date. Så gjør vi en liten endring i a.hpp; touch er det samme som å gjøre en endring i en fil (endrer dato/tid): $ touch a.hpp $ make *** Generating dependencies for a.cpp *** *** Compiling a.cpp *** g++ -c a.cpp *** Linking program *** g++ a.o b.o -o program Så tester vi med b.hpp: $ touch b.hpp$ make *** Generating dependencies for b.cpp *** *** Generating dependencies for a.cpp *** *** Compiling a.cpp *** g++ -c a.cpp *** Compiling b.cpp *** g++ -c b.cpp *** Linking program *** g++ a.o b.o -o program Denne gangen er det flere filer som må rekompileres, dette stemmer bra. :] ..og b.cpp: $ touch b.cpp$ make *** Generating dependencies for b.cpp *** *** Compiling b.cpp *** g++ -c b.cpp *** Linking program *** g++ a.o b.o -o program En kompilering av implementasjonen (b.cpp) og en relink er alt som skal til. Alt ser ut til å fungere, og vi har et lite build-system vi kan bygge videre på her. :] Endret 21. august 2004 av søppel Lenke til kommentar
søppel Skrevet 13. juni 2004 Del Skrevet 13. juni 2004 (endret) Unngå kopiering av objekter #include <iostream> using namespace std; class NoCopy { public: NoCopy() { } // constructor private: NoCopy(NoCopy const&); // Copy constructor. NoCopy& operator=(NoCopy const&); // Assignment }; // NoCopy class A : public NoCopy { public: }; // A int main() { A a; //A b(a); // fails A c; //c = a; // fails return(0); } // main Endret 13. juni 2004 av søppel Lenke til kommentar
søppel Skrevet 18. juni 2004 Del Skrevet 18. juni 2004 Template-policy, kontra polyformi? Dette er muligens litt kørka, men her har jeg satt opp et ex. som viser hvordan man kan velge mellom polyformi eller template-policyes. Begge oppnår omtrent samme effekt i visse tilfeller. a.hpp: #ifndef _A_ #define _A_ #ifdef M_use_policy #define M_virtual #else #define M_virtual virtual #endif class DefaultPolicy { public: M_virtual void doStuff() { // Default code here. // Does nothing; does not // increase counter. } // doStuff }; // DefaultPolicy #ifdef M_use_policy template<typename DOSTUFF = DefaultPolicy> class Base : public DOSTUFF { #else class Base : public DefaultPolicy { #endif public: // Other stuff here. }; // Base #ifdef M_use_policy #undef M_use_poliy #endif #undef M_virtual #endif // #define _A_ a.cpp: #include <time.h> #include <iostream> #define M_use_policy #include "a.hpp" using namespace std; unsigned long counter = 0; // Inheritance is not really necesary here. class TemplatePolicy : public DefaultPolicy { public: void doStuff() { counter++; } // doStuff }; // TemplatePolicy int main() { unsigned long const iterations = 300000000; clock_t s = clock(); Base<TemplatePolicy> a; for(unsigned long i = 0; i < iterations; i++) a.doStuff(); cout << clock() - s << endl; cout << "counter: " << counter << endl; cout << "Used template policy." << endl; return(0); } // main b.cpp: #include <time.h> #include <iostream> #include "a.hpp" using namespace std; unsigned long counter = 0; class VirtualPolicy : public Base { public: void doStuff() { counter++; } // doStuff }; // VirtualPolicy int main() { unsigned long const iterations = 300000000; clock_t s = clock(); Base* b = new VirtualPolicy; for(unsigned long i = 0; i < iterations; i++) b->doStuff(); cout << clock() - s << endl; cout << "counter: " << counter << endl; cout << "Used virtual policy." << endl; return(0); } // main Kjøring av a: $ ./a340000 counter: 300000000 Used template policy. Kjøring av b: $ ./b2720000 counter: 300000000 Used virtual policy. Template-policy-saken er 800% raskere (om jeg ikke regner % feil her nå) enn polyformi-versjonen. :] Lenke til kommentar
søppel Skrevet 20. juni 2004 Del Skrevet 20. juni 2004 Brukerdefinerte argumenter til standard-konstruktøren, i sammenheng med arrayer, Del 2 Fikk kritkk fordi jeg "lagde kode som var unødvendig lang og tåpelig" på news, så her er en versjon som er ennå mer "unødvendig, lang og tåpelig": #include <iostream> template<typename VALUE> struct DefValue { operator VALUE() { return(VALUE()); } // operator VALUE }; // DefValue template<typename VALUE> struct IncValue { operator VALUE() { static VALUE i; return(i++); } // operator VALUE }; // IncValue template<typename T, template<typename> class INIT = IncValue> class Element { public: INIT<T> defaultValue; Element() { _value = defaultValue; } // constructor Element(T value_) :_value(value_) { } // constructor operator T() { return(_value); } // operator T private: T _value; }; // Element int main() { using namespace std; Element<int> arr[10]; for(int i = 0; i < 10; i++) cout << arr[i] << endl; return(0); } // main IMHO så er dette en veldig artig og alternativ måte å gjøre ting på. Maasse muligheter her. Lenke til kommentar
Tr1llobite Skrevet 21. juni 2004 Del Skrevet 21. juni 2004 (endret) Denne er jo litt morsom, den fryser maskinen i 5 sekunder. int before; before = GetTickCount(); SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); while ((before + 5000) >= (int)GetTickCount()) ; SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); return 0; EDIT: LEIF!!!! Endret 28. juni 2004 av kr1570ffz0r Lenke til kommentar
søppel Skrevet 13. juli 2004 Del Skrevet 13. juli 2004 (endret) En virkelig minimalistisk String-klasse Fjernet denne intil videre. :] Endret 21. august 2004 av søppel Lenke til kommentar
søppel Skrevet 11. august 2004 Del Skrevet 11. august 2004 (endret) std::string += "hva-som-helst"? Mange nybegynnere eller de som kommer fra andre språk forventer ofte at noe slikt som dette fungerer: std::string s; s += 123 += "abc"; Det går ikke, siden += ikke returnerer en ref. til s. Vi kan i stedet bruke operator<<, som i sammenheng med std::string er "ledig": #include <iostream> #include <sstream> using namespace std; template<typename T> inline std::string& operator<<(std::string& str, T const& src) { static std::ostringstream oss; oss << src; str += oss.str(); return(str); } // operator<< inline std::string& operator<<(std::string& str, char const* src) { str += src; return(str); } // operator<< inline std::string& operator<<(std::string& str, char* src) { str += src; return(str); } // operator<< inline std::string& operator<<(std::string& str, char src) { str += src; return(str); } // operator<< int main() { std::string s; s << "123" << 321 << "abc" << "987" << 654 << ' ' << 3.1415; cout << s << endl; return(0); } // main 123321abc987321654 3.1415 Edit: Noe av det samme går også for vector og andre konteinere (kan vel diskuteres hvor nyttig dette er): #include <iostream> #include <vector> using namespace std; /// TODO: Specialize for each container type. template<class CONT> inline CONT& operator<<(CONT& cont, typename CONT::value_type src) { cont.push_back(src); return(cont); } // operator<< template<class T> class Print : public unary_function<T, void> { public: void operator()(T src) { cout << src << '\n'; } // operator() }; // Print int main () { std::vector<int> vi; vi << 123 << 321; for_each(vi.begin(), vi.end(), Print<int>()); return(0); } // main Endret 21. august 2004 av søppel Lenke til kommentar
joolae Skrevet 15. november 2004 Del Skrevet 15. november 2004 Passordgenerator der man kan velge hvor langt passordet skal være. #include <conio.h> #include <iostream> #include <string> #include <time.h> using namespace std; int main() { srand(time(0)); string pw = "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ"; int length; cout << "Length of password: "; cin >> length; for (int i = 0; i < length; i++) { int x = rand() % 62; cout << pw[x]; } getch(); return 0; } Lenke til kommentar
knuto Skrevet 14. april 2005 Del Skrevet 14. april 2005 invstring[...]http://www.pastebin.org/index.php?page=sho...&key=y0u4trem1x Hvis du/dere finner noen bugs ta kontakt Unnskyld denne offtopic-tråden, men denne linken til pastebin eksisterar ikkje lenger, og den koden berre må eg få lese gjennom og få inspirasjon! Gjerne slett dette inlegget etter at linken evt. er oppdatert. Lenke til kommentar
epsil Skrevet 30. oktober 2007 Del Skrevet 30. oktober 2007 /**//*/};)/**/main(/*//**/tang ,gnat/**//*/,ABBA~,0-0(avnz;)0-0,tang,raeN ,ABBA(niam&&)))2-]--tang-[kri - =raeN(&&0<)/*clerk*/,noon,raeN){(!tang&& noon!=-1&&(gnat&2)&&((raeN&&( getchar(noon+0)))||(1-raeN&&(trgpune(noon )))))||tang&&znva(/*//**/tang ,tang,tang/**|**//*/((||)))0(enupgrt=raeN (&&tang!(||)))0(rahcteg=raeN( &&1==tang((&&1-^)gnat=raeN(;;;)tang,gnat ,ABBA,0(avnz;)gnat:46+]552&)191+gnat([kri?0>]652%)191+gnat([kri=gnat (&&)1-^gnat(&&)1& ABBA(!;)raeN,tang,gnat,ABBA(avnz&&0>ABBA{)raeN ,/**/);}znva(/*//**/tang,gnat,ABBA/**//*/(niam;}1-,78-,611-,321 -,321-,001-,64-,43-,801-,001-,301-,321-,511-,53-,54,44,34,24 ,14,04,93,83,73,63,53,43,33,85,75,65,55,45,35,25,15,05,94,84 ,74,64,0,0,0,0,0,0,/**/){ABBA='N'==65;(ABBA&&(gnat=trgpune (0)))||(!ABBA&&(gnat=getchar(0-0)));(--tang&1)&&(gnat='n'<= gnat&&gnat<='z'||'a'<=gnat&&gnat<='m'||'N'<=gnat&&gnat<='Z' ||'A'<=gnat&&gnat<='M'?(((gnat&/*//**/31/**//*/,21,11,01,9,8 ,7,6,5,4,3,2,1,62,52,42,/**/)+12)%26)+(gnat&/*//**/32/**//*/, 22,12,02,91,81,71,61,51,41{=]652[kri};)/*pry*/)+65:gnat);main (/*//**\**/tang^tang/**//*/,/* */,~/*//*-*/tang,gnat,ABBA- 0/**//*/(niam&&ABBA||))))tang( rahcteg&&1-1=<enrA(||))tang( enupgrt&&1==enrA((&&)2&gnat(&& )1-^tang(&&ABBA!(;)85- =tang (&&)'a\'=gnat(&&)1-==gnat(&&)4 ==ABBA(&&tang!;))))0(enupgrt= gnat(&&)tang!((||)))0(rahcteg =gnat(&&tang((&&ABBA;;)1-'A'=! 'Z'=tang(&&ABBA{)enrA/***/);gnat ^-1&&znva(tang+1,gnat,1+gnat); main(ABBA&2/*//*\\**/,tang,gnat ,ABBA/**//*/(avnz/**/);}/*//**/ Det ovenstående programmet, westley.c, er Brian Westley sitt vinnerbidrag til The International Obfuscated C Code Contest året 1989. Hvis det kjøres uten argumenter, kopierer det teksten man skriver inn. Hvis det kjøres med ett argument, utfører det ROT13-kryptering på teksten: Hver bokstav fra A til Z byttes ut med den som er 13 plasser frem. (ROT13 av «Hello world», for eksempel, er «Uryyb jbeyq». Utfører man ROT13 to ganger, ender man opp med utgangspunktet, så ROT13 av «Uryyb jbeyq» er «Hello world».) Kjøres det med to argumenter, «reverserer» det teksten, og kjøres det med tre, gjør det begge deler. (Se wesley.hint for mer informasjon.) Det spesielle med programmet er imidlertid at kildekoden kan ROT13-krypteres, «reverseres» eller begge deler, og vil fortsatt kompilere. Hver nye «versjon» av programmet man får på denne måten, anvender en egen algoritme. Og siden programmets oppgave nettopp er å utføre ROT13-kryptering og «reversering», kan de ulike «versjonene» produseres ved å bruke programmet på seg selv: westley < westley.c > ver0.c westley 1 < westley.c > ver1.c westley 1 2 < westley.c > ver2.c westley 1 2 3 < westley.c > ver3.c Sånn. Nå skal jeg gå og legge hodet mitt i bløt. Lenke til kommentar
Anbefalte innlegg
Opprett en konto eller logg inn for å kommentere
Du må være et medlem for å kunne skrive en kommentar
Opprett konto
Det er enkelt å melde seg inn for å starte en ny konto!
Start en kontoLogg inn
Har du allerede en konto? Logg inn her.
Logg inn nå