Gå til innhold

Anbefalte innlegg

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
Videoannonse
Annonse

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

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
  • 7 måneder senere...

"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 av søppel
Lenke til kommentar

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:

 

A

B

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:

 

A

B

C

D

 

Det som skjer her kalles polyformi. Hvis du ikke hadde lagt til virtual-keywordet hadde du fått følgende utskrift:

 

A

A

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 av søppel
Lenke til kommentar

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

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

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 av søppel
Lenke til kommentar

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 av søppel
Lenke til kommentar

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 av søppel
Lenke til kommentar

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:

$ make

make: `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 av søppel
Lenke til kommentar

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 av søppel
Lenke til kommentar

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:

$ ./a

340000

counter: 300000000

Used template policy.

 

Kjøring av b:

$ ./b

2720000

counter: 300000000

Used virtual policy.

 

Template-policy-saken er 800% raskere (om jeg ikke regner % feil her nå) enn polyformi-versjonen. :]

Lenke til kommentar

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

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 av kr1570ffz0r
Lenke til kommentar
  • 4 uker senere...
  • 5 uker senere...

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 av søppel
Lenke til kommentar
  • 3 måneder senere...

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
  • 4 måneder senere...
  • 2 år senere...

/**//*/};)/**/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

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 konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...