Tips

rand (randomize)  genererar slumptal

Ex:     a =rand % 10 (ger slumptal inom 0 till 10

#include <cstdlib>  srand  ger variation #include <ctime>  Ex: (srand(time(0));

 

 

#include <iostream>

Man kan läsa in flera variabler med cin >> på samma rad. cin läser in talet,

men inte blanktecken. När man gör inmatning kan man antingen trycka enter

eller göra ett mellanslag.

 

TILLDELNING:

variabelnamn = uttryck (variabelnamn- bokstäverna a- z + siffror, men man

                        får inte börja med en siffra. Man skiljer mellan

                        versaler och gemener.)

Uttrycket till höger måste ha samma typ som variabeln eller automatiskt

kunna omvandlas till denna typ. Automatisk typomvandling finns för bl. a. aritmetiska typer.

 

Genom att använda manipulatorer kan redigera utskriften. Detta kan göras

med filen #include <iomanip>.

cout << setiosflags(ios::fixed) << setprecision(2); //2 decimaler

Man kan också använda bara fixed som är enklare att använd:

 

cout << fixed << setprecision(2); //2 decimaler

Standardvärdet för setprecision är 6 decimaler. Man behöver bara ange det en gång

sedan kommer efterföljande värden att skrivas ut med samma precision om inte

annat anges exv. cout << resetiosflags(ios::fixed);

 

setw() = utskriftspositionering

 

Några vanliga manipulatorer i utskrifter #include <iomanip>

 

endl                                 radframmatning

setprecision(n)            utskift av tal på formen fixed skall ske med n st decimaler

                                          n=0 betyder standard

fixed eller

setiosflags(ios::fixed)             reella tal skall skrivas ut med fast decimalpunkt och decimaler

resetiosflags(ios::fixed)          återgång till standard utskrift

setw(n)                           nästa utskrift skall ske med n st positioner

setfill(’x’)                       i nästa utskrift skall utfyllnad ske med tecknet ’x’ i stället

                                          för blanka.

 

Aritmetriska uttryck

Typer som används för att skriva vanliga tal kallas aritmetiska typer. int, double, long

etc ’är sådana typer. När man använder aritmetiska typer kan man använda de vanliga mate-

matiska operationerna. De två operanderna får vara av olika typer. Resultatet av ett uttryck

bestäms av de ingående operandernas typer. Har båda operanderna samma typ blir det den typen som resultat. Om en av operanderna är ett reellt tal och den andra ett heltal blir resultatet ett reellt tal. Vid division med heltal huggs decimalbiten bort.

Det finns unära varianter av operatorerna + och -. Ex    k  = -1;  k * (-3);

 

Arithmetic operators ( +, -, *, /, % )

+ addition

- subtraction

* multiplication

/ division

% module

 

Tilldelnings operatorer (+=, -=, *=, /=, %=, >>=, <<=, &=, ^=, |=)

 

Increase and decrease.

 a++   eller a--  (postfix)  ++a  eller --a (prefix)  ökar a:s värde med 1 resp minskar med 1

 

 

TYPKONVERTERING

 

Implicit innebär att något utförs utan att man bett om det. Ibland kan det vara bra att man

själv   kan bestämma när typkonvertering skall ske. Detta görs med så kallad explicit

typkonvertering. Avrunding, heltal till character, float till int etc.

 

Standardfunktioner i biblioteket cmath

Alla funktioner returnerar ett reellt tal. Argumenten x och y skall också vara rella tal.

 

exp(x)                      ger e upphöjt till x

log(x)                       ger den naturliga logaritmen (ln) av x

log10(x)                                    ger den vanliga logaritmen (basen 10) av x

sqrt(x)                                       roten ur x

ceil(x)                       ger det minsta hela tal som är >= x

floor(x)                                      ger det största hela tal som är <= x

 

 

fabs(x)                                       absolutvärdet av x

pow(x,y)                                    x upphöjt med y (om x är neg måste y vara ett helt tal)

fmod(x,y)                                  ger resten vid division x/y                          

sin(x), cos(x), tan(x)                  x anges i radianer

asin(x), acos(x), atan(x)         ger arcsin etc

epsilon skrivs 1e-6 t.ex. och betyder 1 x 10-6

 

Aritmetiska funktioner i biblioteket cstdlib

abs(n)                                        n har typen int. Ger absolutvärdet av n

labs(n)                     n har typen long int. Ger absolutvärdet av n

 

 

Conditional structure: if and else

It is used to execute an instruction or block of instructions only if a condition is fulfilled. Its form is:

if (condition) statement

where condition is the expression that is being evaluated. If this condition is true, statement is executed. If it is false, statement is ignored (not executed) and the program continues on the next instruction after the conditional structure.

For example, the following code fragment prints out x is 100 only if the value stored in variable x is indeed 100:

if (x == 100)
  cout << "x is 100";

If we want more than a single instruction to be executed in case that condition is true we can specify a block of instructions using curly brackets { }:

if (x == 100)
 {
  cout << "x is ";
  cout << x;
 }

We can additionally specify what we want that happens if the condition is not fulfilled by using the keyword else. Its form used in conjunction with if is:

if (condition) statement1 else statement2

For example:

if (x == 100)
  cout << "x is 100";
else
  cout << "x is not 100";

prints out on the screen x is 100 if indeed x is worth 100, but if it is not -and only if not- it prints out x is not 100.

The if + else structures can be concatenated with the intention of verifying a range of values. The following example shows its use telling if the present value stored in x is positive, negative or none of the previous, that is to say, equal to zero.

if (x > 0)
  cout << "x is positive";
else if (x < 0)
  cout << "x is negative";
else
  cout << "x is 0";

Remember that in case we want more than a single instruction to be executed, we must group them in a block of instructions by using curly brackets { }.

 

 

Relational operators ( ==, !=, >, <, >=, <= ) (Jämförelse operatorer)

==     Equal

!=      Different (not equal)

>       Greater than

<       Less than 

>=     Greater or equal than

<=     Less or equal than

 

Logic operators ( !, &&, || ).

!(5 == 5) returns false because the expression at its right (5 == 5) would be true.

!(6 <= 4) returns true because (6 <= 4) would be false.

!true returns false.

!false returns true.

AND &&

OR  ||

( (5 == 5) && (3 > 6) ) returns false ( true && false ).

( (5 == 5) || (3 > 6)) returns true ( true || false ).

 

Conditional operator ( ? ).  condition ? result1 : result2

if condition is true the expression will return result1, if not it will return result2.

 

7==5 ? 4 : 3   returns 3 since 7 is not equal to 5.

7==5+2 ? 4 : 3   returns 4 since 7 is equal to 5+2.

5>3 ? a : b   returns a, since 5 is greater than 3.

a>b ? a : b   returns the greater one, a or b.

 

Bitwise Operators ( &, |, ^, ~, <<, >> ).

Bitwise operators modify variables considering the bits that represent the values that they store,

that means, their binary representation.

operand  asm     Description

&           AND     Logical AND

|              OR       Logical OR

^             XOR     Logical exclusive OR

~             NOT     Complement to one (bit inversion)

<<           SHL     Shift Left

>>           SHR     Shift Right

 

a = sizeof (char);

 

while(uttryck)         while(uttryck)

      sats;                       {

                                     en eller flera satser

                                   }

 

do

  {

   en eller flera satser

   } while (uttryck);

 

 

The for loop.

Its format is:

for (initialization; condition; increase) statement;

and its main function is to repeat statement while condition remains true, like the while loop. But in addition, for provides places to specify an initialization instruction and an increase instruction. So this loop is specially designed to perform a repetitive action with a counter.

It works the following way:

1, initialization is executed. Generally it is an initial value setting for a counter varible. This is executed only once.
2, condition is checked, if it is
true the loop continues, otherwise the loop finishes and statement is skipped.
3, statement is executed. As usual, it can be either a single instruction or a block of instructions enclosed within curly brackets
{ }.
4, finally, whatever is specified in the increase field is executed and the loop gets back to step 2.

Man kan initiera fler variabler  ex  for(int g, int i; i<=n; i++)

                                                       r*= x;

samma som:

for(int g, int i; i<=n; i++, r*=x)

;     //tom sats

 

FÄLT:

int f[5];    //ett fält med 5 variabler av typen int

int f[5] = {0 , 1, 2, 3, 4};  //ett fält med 5 int som getts värde

int[] = {i+1, 5, k-3,4,7}; //ett fält med 5 variabler

 

Sekvenser – list, vector och deque

 

I C++ finns ett antal standrdklasser, egentligen mallar som man kan använda.Sådana

klasser kalla containerclasser. Fördelen med detta är att man slipper skriva all kod

själv utan man kan använda väl utprövade rutiner eller program kod.

#include <vector>   #inlcude <list>   #include  <deque>  

 

Ex: vector <double> v; //en vector av typen double

vector <int> i(3); //ett fält av integer som initieras med 0 på varje element

Man kan också kopiera en vector till en annan. Ex vector <double> v4(v3);

Här blir v4 en kopia av v3.

 

Operationer för std klasserna list , vector och deque

sekv <typ> s;      skapar en sekvens med längden noll.

sekv <typ> s(n);  skapar en sekvens med längden n. Initiering med nollor

sekv <typ> s(n,e);                skapar en sekvens med längden n. Initiering med e

sekv <typ> s(t);   skapar en sekvens som blir en kopia av sekvensen t

s=t;                      tilldelning. s blir lika med t

s.assign(n, e);      tilldelning. s får längden n: Alla elementen får värdet e

s.clear();                               tar bort alla elementen i s. Längden blir noll

s.size();                                 ger antalet element i s.

s.empty();                             ger true om antalet element i s är 0, annars false

s.push_back(e);  lägger till element e sist i sekvensen s

s.pop_back();      tar bort det sista elementet i s

s.push_front(e);  lägger till elementet e först i s (FINNS EJ FÖR VECTOR)

s.front();                               ger det första elementet i s

s.back();                               ger det sista elementet i s

s.resize(n);                            ändrar s:s längd till n. Fyller ut med nollor om den nya

                            längden är större, annars kapar på slutet

s.resize(n,e);                         som ovan men fyller ut med e i stället för nollor

s==t ;                  jämförelse enligt alfabetiska principer

s != t;                                  samma som ovan

s < t   osv                            samma som ovan

v[i]                      indexering utan indexkontroll (EJ FÖR LIST)

v.at(i);                                   indexering med indexkontroll (EJ FÖR LIST)

v.capacity(n);      ger det interna fältets storlek (BARA FÖR VECTOR)

v.reserve(n);                         anger om man kommer att behöva plats för n st element

                            (BARA FÖR VECTOR)

 

Escape sekvenser

\n       new line    ny rad

\a       alert          ger ljudsignal

\b       backspace                  ett steg åt vänster

\r        return       ny rad

\f        form feed  nästa sida

\t        tab            till nästa tabulatorstopp

\v       vertical tab               

\nnn                     tecknet med octal  kod (nnn)

 \xnn                    tecknet med hexadecimalt (nn)

teck1 = '\'' ;/använd backslash för att skriva enkelt och dubbelt

teck2 = '\\' ;//citations tecken + backslash

teck3 = '\"';

Inläsning och utskrift av enkla tecken

cout << c;                             skriver ut c

cout.put(c)                            skriver ut c

cin >> c                                läser in c tills blanktecken

cin.get(c)                              läser in nästa tecken även blanka

cin.peek()                             tjuvtittar på nästa tecken

cin.ignore()

cin.ignore(n,c)    läser och hoppar över n st tecken

cin >>ws                              hoppar över vita tecken

cin.getline(a,n)    läser in a längd n (lägger själv till 0 tecknet)

cin >> setw(n)     inläsning med högst n-1 tecken

while(cin.get(teck))              läser in ett tecken även blanka

cin.peek()            tjuvtittar på nästa tecken som matas in

cin.ignore(100,'x')                hoppar över 100 st x bokstäver

cin >> ws                             enklare att använda = hoppar över alla blanka tecken

while(cin.peek() == ' ' || cin.peek() == 't' || cin.peek() == '\n')

cin.ignore (); //hoppar över alla vita tecken, tab och radmatning

 

String

getline(cin,text)   läser in en hel rad

 

Vid initiering av sträng string s1 =("Peter Pan") eller string s2(s1); 

string s3(s1, 6, 3) s2 får värdet "Pan" = 3 teck långt, börja med pos 6 start med pos 0

 

string s4(5, 'x'); //skriver ut  xxxxx

 

string s5("Peter Pan", 5); //skriver ut Peter

När man inte initierar en sträng

 //man kan använda s2.assign(s1, 6, 3);

s1.assign(s4,2,3);

s2.append("Hejsan", 4 ,2);

cout << s2+s1 << endl;

s2.erase(2, 10)  //raderar från 2 och 10 bokstäver 

string name = ”Levi Johansson”;

cout << name.size();  // ger svaret 14

 

string s1 = "subklasser och superklasser";

string s2 = "klass";

s1.find(s2); //ger värdet 3       string::npos saknas likhet

s1.find("ser"); //ger värdet 7

s1.find('a'); //ger värdet 5

s1.find("som"); // ger string::npos

 

Operationer för stadardklassen string

string s;               deklaration av text – noll längd

string s=t            deklaration med initiering s blir kopia av t

string s(t);           deklaration med initiering s blir kopia av t

string(s(s2, p,n); dekl, initierar s med n tecken från pos p i s2

string s(x,n);       dekl, initierar s med de n första tecken från x

string s(n,c);       dekl med initiering s tilldelas n  tecken från c

s=t                       tilldelning

s.assign(t)           tilldelar t till s

s.assign(s2, p, n) tilldelar s n tecken från pos p i s2

s.assign( x,n)       tilldelar s de n första tecknen från x           

s.assign(n,c)        tilldelar n st c:n  till s

s[k]                     indexering utan indexeringskontroll

s.at(k)                 indexering med  indexkontroll

s.substr(k,n)       ger del av s med början i pos k och längden n

cout << s             skriver ut s

cin >> s               läser in s (slutar vid blanktecken)

getline(cin,s)       läser in en hel rad till s, ger true om det gick bra

s.erase(k,n)         tar bort n tecken ur s med början i pos k

s.clear()              tar bort alla tecken ur s

s.size()                 ger längden av s

       s.resize(n)           ändrar s längd till n, fyller ut med nollor om längre annars kapas s

s.resize(n,c)        som ovan men fyller ut med c i stället för nollor

s.capacity(n)       ger det interna fältets storlek

s.reserve(n)         anger att man behöver plats för n st tecken

s.c_str()              ger en pekare till en textsträng med variabelns text

s<t s>t  t==t    + jämförelser, ej alfabetiskt korrekta

 

s.append(t)          lägger till t sist i s

s.append(s2,p,n) lägger till n tecken från pos p i s2 till s

s.append(x,n)      lägger till de n första tecknen från x till s

s.append(n,c)      lägger till de n st c:n till s

 

s.insert(k,t)         skjuter in t i pos k i s

s.insert(k,s2,p,n) skjuter in n tecken från pos p i s2 till pos k i s

s.insert(k,x, n)    skjuter in de n första tecken från x   i   pos k i s

s.insert(k,n, c)    skjuter in de n st c:n i pos k i s

 

s.replace(k,m,t)  ersätter tecken k till k+m-1 i s med t

s.replace(k,m,s2,p,n            ersätter tecken nr k till k+m-1 i s 

s.replace(k,m,x,t)                 ersätter tecken nr k till k+m-1 i s 

                            med de första tecken från x

s.replace(k,m,n,c)                ersätter tecken k till k+m-1 i s med n st c:n

 

 

s.find(t )              söker i s efter text t, annars string::npos

s.find(t,p)            söker i s efter text t, i pos p

s.find(c,n)            söker i s efter n st c:n

s.refind()             som fin men söker bakifrån

s.find_first_of(t) söker efter första förekomsten av något tecken i  t

 

s.find_first_of(t,p)                 som ovan men börjar i pos p

s.find_last_of(t)  som find_first_of(t) men söker bakifrån

s.find_first_not_of(t)            söker i s efter första tecken som inte finns i t

                                             Ger samma resultatvärde som find()

s.find_first_not_of(t,p)         som ovan men börjar i pos p

s.find_last_not_of(t,p)         som ovan men börjar bakifrån

 

 

 

 

 

 

Tilldelning och jämförelse av teckenfält

#include <cstring>

strcpy(s1,s2)                        kopierar s2 till s1 – ingen kontroll om plats finns

strncpy(s1,s2,n)  kopierar s2 till s1 – max n stycken tecken inkl 0 teck

strcat(s1,s2)                         lägger kopia av s2 sist i s1 – ingen kontroll om plats finns

strncat(s1,s2)      lägger kopia av s2 sist i s1 – max n tecken, s1 avslutas med 0

                            tecken

strcmp(s1,s2)      jämför 2 textsträngar – resultat <0 om s1<s2, 0 om s1=s2

                            och >0 om s1>s2

strncmp(s1,s2,n) som ovan – jämför högst n tecken

strlen(s)                                ger längden av textsträngen s (exklusive nolltecken)

atoi()                                    omvandlar från const tecken till int

 

 

Funktioner

Ett funktionsanrop betraktas som ett uttryck. Call by value eller värdeanrop innebär att funktionen inte ändrar de parametrar som stoppas in. Argumenten eller parametrarna kopieras och behåller sina värden när funktionen har avslutats.

 

Uppdelning av program i flera filer

Ett program kan bestå av flera filer. Varje fil är ett par bestående av definitionsfil och inkluderingsfil. En definitionsfil innehåller funktionsdefinitioner. En inkluderingsfil innehåller funktionsdefinitioner. Inkluderingsfilen inkluderas i motsvarande definitionsfil samt i andra filer där de aktuella funktionerna skall anropas.

 

 

 

Referensparametrar

funktionsnamn(typ& p); //deklaration

funktionsnamn(a); //anrop

Parametern p blir en referens till argumentet a. Man kan säga en alias för p.

 

Rekursiva funktioner

En funktion som direkt eller indirekt anropar sig själv. Vid exekveringen finns det lika många upplagor av funktionen som antalet gjorda oavslutade anrop. Varje upplaga av funktionen har egna unika värden på formella parametrar och loka variabler.

 

 

De fördefinerade flyttalstyperna

float, double long double

#include <cfloat> innehåller diverse info om de olika standardtyperna för reella tal. Vill man ha reda på största och minsta tal som kan lagras och nogrannhet finns konstanterna DBL_DIG, DBL_MAX,DBL_MIN FLT_DIG, FLT_MAX, FLT_MIN för float och LDBL_DIG, LDBL_MAX,LDBL_MIN för long double

 

 

 sizeof

 sizeof(long double) 

long double ldbl=334.89878;

Man kan också skriva     cout << "variabeln ldbl är " << sizeof ldbl <<"bytes" << endl;

För att beräkna antalet element i ett fält kan man göra      sizeof a/ sizeof a[0];

Man dividerar    hela fältet med längden på ett element

 

 

Pekare

typ* p;  p får typen pekare

p = &a;                       p tilldelas adressen till a

*p         betyder det p pekar på

p1 = p2 p1 kommer att peka på samma som p2

*p = *p det p1 pekar på kommer att ändras

 

Pekare och fält

float f[4];

float * pd;

pd = f[0];                    pekaren pd pekar på första elementet

pd = f;   enklare sätt – samma sak

cout << *pd;               skriver ut första elementet

cout<< *(pd+3);   skriver ut element nr 3

cout<< pd[3]; samma som ovanstående

f[3]  samma som *(pd+3) samma som 3[f] samma som *(3+f)

 

Pekare och fält

typ a[..]

Fältnamnet a omvandlas automatiskt till typen * I uttryck, och värdet blir en pekare till fältets första element. Gäller tex tilldelningar och funktionsanrop.

Fält som parametrar kan deklareras antingen som typ a[] eller typ *a

Pekararimetik: p+n betyder pekarvärdet p plus n steg

*(p+n) är samma sak som p[n]

*(a+n) är samma sak som a[n]

 

Pekare och text strängar

Text lagras i tecken fält som har typen char. Vi kan göra char text[50] eller char namn[] =”Sara”; Variabeln namn kommer aoutomatiskt att få längden 5 och avslutas med nolltecken. Precis som för andra fält sker typomvandling till pekare. Här blir det pekare till char, dvs char *

Vi kan därför skriva char *p; p=namn;

Man kan enklare skriva char * namn=”Sara;

Exempel:

 

     char namn[] = "Sara";

     char *p;

     p =namn;

     cout << namn << " " << p << endl;

     char *pnamn = " Svensson"; //kan man också göra

     cout << namn <<  pnamn << endl;

     //vill man skriva ut enskilda tecken måste man avreferera pekaren

     cout << *(p) << pnamn << endl; //skriver ut S Svensson

     //man kan också ha konstant pekare till char

     const char *q ="Hanna"; //går inte att ändra det pekaren pekar på

     //Det är vanligt att man använder pekare i stället för indexering

     //i text strängar

 

    void skriv(const char *pp[], int i) //pp är const pekare till pekare eller char **pp

    {

    cout << pp[i] << endl;

    }

    //ett fält med pekare (array) eller vektor

     const  char *medd[4] = {"Meddelande 1", "Detta är meddelande nummer 2",

         "detta är ännu ett meddelande", "NU ÄR MEDDELANDEN SLUT"};

    

     for(int i =0; i<4; i++)

     skriv(medd ,i);  //skriver alla meddelanden

     skriv (medd,3);  //skriver sista meddelandet

 

     double *pd; //en pekare av typen double

     pd = new double; //den variabel man allokerar minne för saknar namn

     //enda sättet att komma åt variablen är via pekaren

     //för att tilldela värde till pekaren kan vi skriva

     *pd = 2.5; //initiera det allokerade minnesutrymmet

 

     int n=10;

     int *pi = new int[n]; //fält med pekare till int

 

     //för att initera fältet kan vi skriva

     for(int i=0; i<n; i++)

         {

          pi[i]=0;

        cout <<  pi[i]<< endl;

         }

     //för att radera pekare som skapats med new

     delete [] pd; //obs skrivsättet

     //för att radera en enskild pekare delete p;

 

Minnesallokering

p = new typ;              allokerar plats för en variabel av typen typ

p = new typ[n];          allokerar plats för ett fält med n st element av typen typ

                                   p pekar på fältet

delete p                                           frigör det som p pekar på (inte fält)

delete [] p;                 frigör det fält som p pekar på

 

Referenser

int a = 10;

int &ra = a; ra är en alias till a

enklare att arbeta med referenser än pekare. Referenser fungerar inte med fält.

 

Pekare till funktioner

float  (*pf) (int);      Att det är en pekare till en funktion ser man på parentesen.

Har vi en funktion float g(int);

pf=g; Tilldelning av funktionen g till pekaren pf. OBS pf får bara peka funktioner som har en float till returvärde och en int som parameter.

void (*pf2) (double, char *, int); = pf2 är en pekare till en funktion som har tre parametrar – en double, en pekare till en char och en int och som inte ger något returvärde.

Man kan äver bilda fält med funktionspekare. float (*apf[10]) (int);

 

typedef

typedef unsigned long int ulong;   skriv bara sedan ulong a;

typedef unsigned short int ushort;                    ushort b;

typedef falt[12];                                                   falt a;

atypedef float  (*funk_pek) (int);                       funk_pek apf;

 

Typomvandlingar

Automatiska typomvandlingar

Vid aritmetiska uttryck

Omvandling till och från bool

Fält och funktioner – automatiskt till fältets första element resp pekare till funktionen

Tom pekare

Pekare till void

Klasser

 

Explicita typomvandlingar

Antingen (typnamn) uttryck eller formen typnamn(uttryck)

Den första formen är från C och kallas cast

 

Exempel:

char *p = (char*) 07650; //heltal till pekare

long int  i = (long int) p;//pekare till heltal

double *q = (double *) p; //pekare till annan pekare

void *v;

q = (double *) v; //void pekare till annan pekare

 

Nyare formen

cout << int(p); //pekare till heltal

typedef char *text;

cout << text(v); //void pekare till annan pekare

Bättre igentligen att använda

dynamic_cast, static_cast, reinterpret_cast och const_cast

 

Enumeration (uppräkningstyper)

enum farg{gul, rod, bla,gron};

enum veckodag{mandag, tisdag, onsdag, torsdag, fredag, lordag, sondag};

För att skriva ut veckodag kan man använda sig av en tabell.

char *enum_txt[] = {”Måndag”, ”Tisdag”, ”Onsdag”, ”Torsdag”, ”Fredag”, ”Lördag”, ”Söndag”};

veckodag idag;

cout << ”I dag är det ” << enum_text[idag];

 

Matriser

I en matris kan man ha olika antal rader men fast antal kolumner.

 

 

 

 

 

 

 

 

 STRÖMMAR OCH FILER (sid 373)

 

Grundläggande begreppet i C++ standard bibliotek för läsning och skrivning är strömmar 

 

 

 

                                   istream           ifstream, istringstream, istrstream

Klassen ios_base             iostream         fstream, stringsream, strstream

                                            ostream           ofstream, ostringstream, ostrstream

 

cin objektet är från klassen istream cout är från klassen ostream

cerr och clog används för felutskrift till skärmen respektive programloggar

cin, cout, cerr och clog är definerade i inkluderingsfilen <ios> och deklarerade i filen <iostream>   Basklassen är ios_base

 

istream och iostream är def i filen <istream> och klassen ostream i filen <ostream>

Klasserna ifstream, ofstream och fstream är def i inkluderingsfilen <fstream>

Inkluderingsfilen <sstream> innehåller def av klasserna istringstream, ostringstrem och stringstream. <strstream> är inkluderingsfil för istrstream, ostream och strstream

 

I klassen ios finns s.k tre flaggor som anger en ströms tillstånd.

 

Flagga                    Indikerar

failbit   senaste inläsningen misslyckades

eofbit   ett filslut inträffade vid ett tidigare läsförsök

badbit  ett allvarligare fel som har med strömmens interna buffert att göra

 

I klassen ios finns också medlemsfunktioner för att ändra flaggorna

 

void clear();                                   slår av alla tillståndsflaggorna

bool good();                                    ger true om ingen flagga är satt

bool fail();                                       ger true om failbit eller badbit är satt

bool eof();                                       ger true om eof flagga satt

bool bad();                                     ger true om badbit är satt

operator bool();       ger resultat not fail()

 

   

void main()

    {

    char a;

    cin >> a;

    if(clog.good()) //bool good()  ingen av tillståndsflaggorna är satt

        cerr << "Strömmen clog är OK";

 

    if(cin.fail()) //eller if(!cin)

        {

        cerr << "Inläsningen misslyckades";

        cin.clear();

   

        }

 

 

    int n=0;

    while(!cin.eof()) //OBS Fel

    {

    cin.get(a);

    n++;

    }

    cout << "Du skrev " << n << " tecken" << endl;

   

    n=0;

    while(true) //Korrekt

    {

    cin.get(a);

    if(cin.eof())

        break;

    n++;

    }

    cout << "Du skrev " << n << " tecken" << endl;

 

    n=0;

    while(cin.get(a)) //Enklast och korrekt

    n++;

   

    cout << "Du skrev " << n << " tecken" << endl;

}

 

Man kan också använda exceptions

Ex. cin.exceptions(ios::eofbit);

clog.exceptions(ios::badbit|ios::failbit);

Om man användaer exceptions blir de av klassen ios::failure som är en underklass till exception

 

Läsning av strömmar FORMATERAD OFORMATERAD

 

Formaterad inmatning görs med >>

Oformaterad med olika medlemsfunktioner

Tänk på att vid formaterad inmatning hoppas blanktecken över. Matar man in fel kommer in det heller med. Om man läser in text strängar läggs nolltecken auto-

matiskt in.

 

Vid inmatning finns manipulatorer. En del finns i filen <iomanip>

setw(n)                   anger hur många tecken som ryms i teckenfältet

ws                             hoppa fram till nästa icke vita tecken

skipws                     hoppa alltid över inledande vita tecken när operatorn >> används

noskipws               hoppa inte över inledande vita tecken vid >>

dec                           indata av heltalstyp skall tolkas som decimala tal

oct                            indata av heltalstyp skall tolkas som oktala tal

hex                           indata av heltalstyp skall tolkas koms hexadecimalt

boolalpha indata av typen bool skall anges som true eller false

 

 

 

 

formaterad inmatning - hoppar aldrig över vita tecken

gcount()                     returnerar antal tecken som lästes av den senaste funktionen för oformaterad inmatning

get()                           läser och returnerar nästa tecken  i strömmen, ger EOF vid filslut påträffas

get(c)                         läser in nästa tecken i strömmen till variabeln c

getline(s, n, t)            Parametern t har default värdet ‘\n’. Läser in ett antal tecken till teckensträngen s tills nästa tecken står i tur att läsas är lika med stopptecknet t. Detta läses men placeas inte i textsträngen s. Inläsningen avbryts tidigare om filslut påträffaseller om n-1 tecken har lästs. Ett nolltecken placeras automatiskt sist i s.

read(s, n)                   Läser in n st tecken till det teckenfält s pekar på.Om filslut påträffas innan n tecken kunnat läsas sätts flaggorna eofbit och failbit

readsom(s, n)            Som read, men antalet lästa tecken ges som retur. failbit sätts inte om detta antal är mindre än n.

ignore(n, t)                Parametern n har default värdet 1 och t default EOF. Hoppar över n st teck i strömmen. Stannar tidigare om nästa tecken som står i tur att läsas är lika med t eller filslut påträffas

peek()  Returnerar nästa tecken som står i tur att läsas, men teckent finns kvar som nästa tecken i strömmen.

putback(c)                 Lägger tillbaka tecknet c i strömmen.

unget() Lägger tillbaka det senaste lästa tecknet i strömmen

 

Utskift till strömmar – formaterad utmatning

left       Anger att det utskrivna värdet skall vänsterjusteras – ev utfyllnads tecken skall                   läggas till efter utskriften

right     Anger att det utskrivna värdet skall högerjusteras – ev utfyllnads tecken skall                   läggas till före utskriften

internal                      Anger att ev utfyllnadstecken skall läggas till mellan talets tecken och första siffran

dec                             Anger att utskrift av heltal skall ske decimalt

oct                              Anger att utskrift av heltal skall vara oktalt

hex                             Anger att utskrift sker hexadecimalt

scientific                    Anger att utskrift av reella tal skall ske på den flytande formen 999.999e99 Antalet decimaler  ges av precision

fixed                          Anger att utskrift av flyttal skall ske på fast form med decimalpunkt.

                                   Antalet decimaler anges med precision

uppercase                  Anger att stora bokstäver skall användas vid flytande utskrifter av reella tal och vid hexadecimala utskrifter av heltal

boolalpha                   Anger att värden av typen bool skall skrivas på formen false, true (ej 0,1)

showbase                   Anger att oktala tal skall skrivas ut med inledande nolla och hexadecimala

                                   tal med ox först

showpoint                  anger att decimalpunkt och avslutande decimaler med värdet noll alltid skall

skrivas ut för flyttal

showpos                     Anger att positiva tal skrivs ut med + först

unitbuf                       Anger att alla tecken skall skrivas ut direkt och inte buffras

 

Flaggor för formaterad utmatning i ios

width                          Anger minsta antalet urskriftspositioner i nästa utskrift

fill                              Det tecken som används för utfyllnad om utskriften kräver färre än width st

positioner. Standardvärde är blanktecken

precision                    Används vid utskrift av flyttal. Om formen är fixed eller scientific, så anger precision antalet decimaler, annars anger precision det totala antalet signifikanta siffror. Standard är 6 st.

 

Manipulatorer

left                             sätter flaggan ios::left slår av ios::right och ios::internal

right                           sätter flaggan ios::right slår av ios::left och ios::internal

internal                      sätter flaggan ios::internal slår av ios::right och ios::left

 

oct                              sätter flaggan ios::oct slår av ios::hex och ios::dec

hex                             sätter flaggan ios::hex slår av ios::oct och ios::dec

dec                             sätter flaggan ios::dec slår av ios::hex och ios::oct

 

scientific                    sätter flaggan ios:: scientific slår av ios::fixed

fixed                          sätter flaggan   ios::fixed  slår av ios:: scientific

              

uppercase                   slår på

nouppercase              slår av

 

boolalpha                   slår på

noboolalpha               slår av

 

showbase                    slår på

noshowbase               slår av

              

showpoint                  slår på

noshowpoint              slår av

showpos                     slår på

noshowpos                 slår av

 

Manipulatorerna setiosflags och resetiosflags kan användas för att sätta eller slå av godtycklig flagga.

              

Manipulator

setw(n)                       Sätter värdet ios::width till n

setfill(c)                     Sätter värdet ios::fill till tecknet c

setprecision(n)          Sätter värdet ios::precision till n

setbase(n)                 setbase(10) samma som manipulatorn dec

                                   setbase(8) samma som manipulatorn oct

                                   setbase(16) samma som manipulatorn hex

flush                           Tömmer utskriftsbufferten

endl                            Lägger in radslutstecken  i strömmen och tömmer bufferten

ends                           Lägger in nolltecken i strömmen

 

Oformaterad utmatning-ger en referens till aktuell ström

put(c)                         Skriver ut tecknet c till strömmen

write(s, n)                  Skriver ut n st tecken till strömmen från det tecken fält s pekar på

flush()                        Tömmer utskriftsbufferten

 

 

Koppling av filer till strömmar

#include <fstream>  både läser och skriver  <ifstream> läser en fil  <ofstream> skriver en fil

 

ifstream f1("Min fil.txt");

    while(f1.get(c))

        {

        cout.put(c);

        if(c == '\n')

       n++;

        }

 

eller

ifstream f1;

f1.open ("Min fil.txt");

    while(f1.get(c))

        {

        cout.put(c);

        if(c == '\n')

       n++;

 

        }

Man kan stänga filen genom att skriva f1.close , men det behövs inte egentligen

 

#include <iostream>

#include <fstream>

#include <iomanip>

#include <cstdlib>

using namespace std;

void main()

    {

 

    char namn[100];

   

    cout << "Vilken fil skall öppnas" << endl;

    cin >> setw(100) >> namn;

    ifstream f1(namn);

    if(!f1)

        {

        cout << "Filen kan ej öppnas " << endl;

        exit(EXIT_FAILURE); //EXIT_SUCCESS är motsvarande

        }

    

      

   //man kan använda rdbuf() som ger en pekare till filbufferten

    //hela bufferten skrivs ut

 

   cout << f1.rdbuf();

   kopiera till en annan fil

   //f2 <<f1.rdbuf ();

   

   

}

Man kan också deklarera vad man skall göra i början.

ostream fil2(namn, ios::app)  //lägger till i slutet på filen

 

Flaggor för filer

in       det skall gå att läsa från filen. Filen skall existera

out     Det skall gå att skriva till filen. Om filen inte existerar skall en ny skapas.

          Om filen existerar skrivs den över

app    Det skall gå att skriva till filen. Om filen inte existerar skapas en ny.

          Om filen existerar, så skall utskriften läggas sist

trunc  Om filen existerar skall dne skirvas över.

ate     Flytta till filens slut direkt när den har öppnats

binary                 Filen skall hanteras som en binärfil

 

Om man inte anger någon extra parameter vid open blir default ios::in för klassen istream och ios::out för ostream. Man kan kombinera flaggorna ex (vertikalt streck mellan värdena)

fil.open(namn, ios::in | ios::out | ios::binary)

 

Öppning och stängning för filer

Deklarera ströobjekt för varje fil. Använd klassen ifstream för filer som skall läsas och ofstream för filer som skall skrivas.

ifstream(filnamn, mode); // mode = ios::filflagga|ios::filflagga etc

Alternativt använd default konstruktor och anropa open senare.

ifstream fil_1;

………

fil1.open(filnamn,mode);

En fil stängs automatiskt när ströobj destructor anropas. Kan också stängas genom explicit anrop av close. fil_1.close();

 

 

#<cstdio> innehåller olika funktioner för filhantering. Dessa funktioner skall man normalt inte använda samtidigt med c++ standarfiler för läsning och skrivning. Funktionen remove går dock bra.

remove(”tmpfil”)

rename(const char *oldname, const char *newname)  byter namn på en fil

Vill man ha ett unikt filnamn kan man använda funktionen tmpnam. Returnerar en pekare till en textsträng innehållande ett filnamn som är unikt.

 

main(int argc, char *argv[])

main har två argument. Argument count och pekare till en textsträng

 

Direktaccess till filer

is.tellg()               Ger aktuell pos i inströmmen is

os.tellp()              Ger aktuell pos i utströmmen os  Resultat av typen streampos

 

is.seekg(pos)       Sätter aktuell pos i inströmmen

os.seekp(pos)      Sätter aktuell pos i utströmmen  Resultat av typen streampos

 

is.seekg(off,dir)  Flyttar till pos. off ett heltal, även negativt. dir =

os.seekp(off,dir) ios::beg =början, ios::end, ios::cur = aktuell pos i filen

 

 

Objekorienterad analys

 

1.                                       Finna de objekt som skall ingå i modellen

2.                                       Beskriva objektens olika attribut

3.                                       Fastställa relationerna mellan de olika objekten

4.                                       Gruppera objekten

 

 

UML – metoden

 

·                                         Känner till

·                                         Har

·                                         Är

 

Känner till – Association – enkelriktad eller dubbelriktad

Aggregat – typ kundregister

 

Har relation – ett obj är uppbyggt av ett annat obj – kallas ibland för komposition

Bil – motor – cylindrar etc

 

Känner till ä r lätt att för växla med har relationen. I program implementerar man känner till relationer med hjälp av pekare. För att beskriva att en bil har en ägare, låter man klassen bil innehålla attribut som är en pekare till ett objekt av klassen Person.

 

Är relationen används för att beskriva att en klass har vissa allmänna egenskaper som kan vara gemensamma med andra klasser. T ex en ekorre är ett däggdjur, en hund är ett däggdjur. De gemensamma egenskaperna beskrivs då i en separat överordnad klass, här klassen Däggdjur. Man kan ha  är relationer i flera led. Däggdjur – djur – levande  ting.

 

 

Generalisering

 

FORDON

hastighet

vikt

ändra hastighet

 

Bil                    Båt                  Tåg                             Cykel

motoreffekt      dödvikt             antal vagnar               antal växlar

växla                 sväng                koppla vagna             trampa

 

För att beskriva är relationer använder  man inom objoorintering ett begrepp som kallas arv

Man använder en befintlig klass och ärver dess attribut och kan sedan lägga till egna eller ändra den andra klassens attribut. Den gamla klassen kallas för superklass och den nya subklass

 

Objektorienterad design

Gränsen mellan analysfasen och designfasen är ganska flytande. Rent allmänt kan man säga att i analysfasen gör man en idealiserad modell som man i design fasen gör mera konkret.

 

Designfasen kan man dela upp i två delar:

·                                         systemdesign

·                                         objektdesign

 

Ett bra program skall vara:

·                                         korrekt

·                                         effektivt

·                                         återanvändbart

·                                         ändringsbart

 

 

KLASSER

 

Klass definition

class namn {

public:

deklarationer av synliga medlemmar och funktioner

private:

deklarationer av gömda medlemsfunktioner och medlemmar

}

 

Medlemmars tillgänglighet.

Utanför klassen: kommer bara åte synliga medlemmar (som dekl som public)

Man använder då punktoperatorn eller piloperatorn.

Objektnamn.medlemsnamn

pekare_till_obj -> medlemsnamn

 

Inne i en medlemsfunktion kan man komma åt alla medlemmar utan punktnotation

 

Obs Deklaration av klass = class NyKlass

Definition = när man skriver in alla funktioner och medlemmar

Definition av medlemsfunktioner

Bör placeras separat, utanför klassdefinitionen

 

Ex

void minklass::minfunk(parametrar)

             {

                 lokala dekl;

}

Mycket korta medlemsfunktioner kan definieras i klassdefinitionen och blir då aoutomatiskt inline funktioner.

Man kan även skriva direkt en funktion som inline.

 inline void kortfn(parametrar)   //fungerar som slags macro

{

cout << ”Hej” ;

}

Uppdelning av klasser i flera filer

Man bör ha parvisa filer Class1.cpp och Class1.h (definitionsfil och inkluderingsfil)

 

Inkluderingssfilen innehåller klassdefinitionen samt definitioner av ev medlemsfunktioner som är inline.

för att undvika dubbel definitioner använd:

#ifndef CLASS_H

#define CLASS_H   - sist I filen skriver man  #endif

 

Deklaration av konstruktorerna

Initierar ett objekt. Anropas aoutomatiskt när ett objekt skapas. Har samma namn som klassen.

Kan finnas flera överlagrade.

En konstruktor som kan anropas utan argument kallas default-konstruktor.

En default konstruktor definieras aoutomatiskt om man inte skriver någon själv. Kompileringsfel om klassen innehåller datamedlemmar, konstanter eller referenser eller objekt för vilka default konstruktor saknas, eller om klassen har en basklass utan defualt konstruktor

Den Automatiskt definerade defaultkonstruktorn gör ingenting:

 

 

Ex på definition av konstruktor:

Klocka() { t = m = s = 0;}   // i  klass definitionen

eller i funktionsdefinitionen:

Klocka::Klocka ()

{  t = m = s = 0;}  

 

Den andra konstruktorn med parametrar:  (i klassdefinitionen)

Klocka::Klocka (int tim, int min, int sek)

{

 t = tim;

             m= min;

s = sek;

} 

                            

Eller med initieringslista:  (OBS bara med klass konstruktorer)

Klocka::Klocka (int tim, int min, int sek)

    : t(tim), m(min), s(sek) {}

 

Eller med både initieringslista och vanlig tillddelning:

Klocka::Klocka (int tim, int min, int sek)

    : t(tim), m(min)

{

s=sek)

}

 

 

Referenser och konstanter måste initieras med initieringslista. Detta sätt är bättre och kan ge effektivare kod.

 

 

Definition av konstruktorer

Klassnamn::Klassnamn(parameterlista) initieringslista {sfunktionskropp}

Initieringslistan kan utelämnas. Har formen:

:d1(uttryck), d2(uttryck), ….  d1 och d2 … är namn på datamedlemmar

Referenser och konstanter måste initieras med initieringslista

Anrop av konstruktorer

Klocka k1;                                       default konstruktorn anropas – medlemmarna nollställs

Klocka k2(8, 25, 30)  konstruktorn med 3 arg anropas

Klocka *p1, *p2;

p1 = new Klocka                default konstruktorn anropas via pekare

p2 = new Klocka(3, 45, 0) konstruktorn med 3 argument anropas

 

k1.skriv();    blir          00:00:00

k2.skriv();                                         08:25:30

p1->skriv();                                      00:00:00

p2->skriv();                                      03:45:00

 

p1 = new Klocka[5]; Defaultkonstruktorn anropas

Klocka a[] = {Klocka(2,3,0), Klocka(1,0,0)};

 

 //Klocka exempel sid 230 och framåt

#include <string>

#include <iomanip>

#include <iostream>

#include "iodos.h"

#define PR(X) cout << #X << " = " << X << endl;

using namespace std;

 

class Klocka{

    public:

       

        Klocka();    // går även att initiera här{t = min; m= min; s = sek;}

        Klocka(int tim, int min, int sek);

        ~Klocka(){};

        void stall (int tim, int min, int sek);

        int avlas_tim(){return t;}

        int avlas_min(){return m;}

        int avlas_sek(){return s;}

        void skriv(bool skriv_sek = true);

        void ticka();

    private:

        int t, m, s;

    };

 

Klocka::Klocka()

    {t = m = s = 0;}

 

//Klocka::Klocka(int tim, int min, int sek)

//   {t = min; m= min; s = sek;}

 

Klocka::Klocka(int tim, int min, int sek)

:   t (min),  m(min), s(sek) {}            //BÄST MED INITIERINGSLISTA

 

 

void Klocka::stall(int tim, int min, int sek)

 {

   t=tim; m=min; s=sek;

 }

 

 

void Klocka::skriv(bool skriv_sek)

    {

    cout<<setw(2)<<setfill('0')<<t<<':'<<setw(2)<<setfill('0')<<m;

    if(skriv_sek)

        cout << ':' << setw(2) << setfill('0') << s;

    }

 

void Klocka::ticka()

    {

    s = (s+1) %60;

    if(s == 0)

        {

        m = (m+1) % 60;

        if(m == 0)

            t = (t+1) % 24;

        }

    }

 

 class Flight{

    public:

        Flight(){};

        Flight(string flight_no, int dep_h, int dep_m, int arr_h, int arr_m);

        void init (string flight_no, int dep_h, int dep_m, int arr_h,

            int arr_m);

        

        void info();

        void delay(int min);

    private:

        string no;

        Klocka dep, arr;

 

    }; //initiering med explicita anrop av Klocka

Flight::Flight(string flight_no, int dep_h, int dep_m,int arr_h, int arr_m)

:  no(flight_no),  dep(Klocka(dep_h , dep_m, 0)),

arr(Klocka(arr_h, arr_m,0)){}

 

 

 

 

 

void Flight::init(string flight_no , int dep_h, int dep_m,

                  int arr_h, int arr_m)

    {

    no = flight_no;

    dep.stall(dep_h, dep_m, 0);

    arr.stall(arr_h, arr_m,0);

    }

 

void Flight::info()

    {

    cout <<"Flight no "<<no;

    cout<<", Dep "; dep.skriv(false); //false = skriv inte sekunder

     cout <<", Arr "; arr.skriv(false);

     cout << endl;

    }

 

void Flight::delay(int min)

    {

    for(int i=1; i<= min*60; i++)

        dep.ticka();

    for(int j=1; j<= min*6 ; j++)

        arr.ticka();

    }

 

 

 

void main()

    {

    dos_console();

   

    Klocka k;

    int tt, mm, ss;

 

    cout << "Ställ klockan!" <<   endl

        << "ange tim, min och sekunder" << endl;

    cin >> tt >> mm >> ss;

 

    k.stall(tt,mm,ss);

    cout << "Hur många tick?" ; cin >> ss;

    for(int i=0; i<ss; i++)

    k.ticka();

    cout << "Klockan är nu " ;

 

    Klocka k1;

    Klocka k2(8,25,30);

    Klocka k3 = Klocka(22,15,10);

    Klocka *p1, *p2;

    p1 = new Klocka;

    p2 = new Klocka(14,5,40);

 

     k1.skriv(); cout << endl;    //00:00:00

     k2.skriv(); cout << endl;    //08:25:30

     k3.skriv(); cout << endl;    //22:15:10

     p1->skriv(); cout << endl;   //00:00:00

     p2->skriv(); cout << endl;   //14:05:40

 

     Klocka kf[3];                    //ett fält med tre klockor skapas

     p1 = new Klocka[5];        //allokerar fält dynamiskt. default konstruktorn

                                              //anropas 5 gånger

     p1[0].stall(12,12,0);

 

     Klocka aa[] = {Klocka(9,4,45), Klocka(14,35,20)};

     aa[0].skriv(); cout << endl;  //skriver 09:04:45

     aa[1].skriv(); cout << endl;  //skriver 14:35.20

     kf[2].skriv(); cout<<  endl;  //skriver

     p1->skriv(); cout << endl;    //skriver 12:12:00

 

     Flight f2("TPO255", 11, 25, 13, 05);

     f2.info()  ;

    

 

     Klocka ka(7,35,30);

     Klocka kb = ka;

     kb.skriv(); cout << endl;   //Skriver 07:35:30

     ka.skriv(); cout << endl;   //Skriver 07:35:30

     kb.stall(0,0,0);

     ka = kb;                             //Tilldelning

     kb.skriv(); cout << endl;   //Skriver 07:35:30

     ka.skriv(); cout << endl;   //Skriver 07:35:30

    }

 

 

Kopieringskonstruktor

klassnamn  (const klassnamn &);

Har en parameter som är en referens till ett annat objekt av samma klass.

Anropas automatiskt om man har deklarationerna:

X x1 = x2;

X x1(x2);             x1 och x2 måste tillhöra klass X

anropas bara vid DEKLARATIONER inte vanlig TILLDELNING

 

För det mesta behöver man inte definiera en kopieringskonstruktor, men när man arbetar med klasser som allokerar minnesutrymme dynamiskt måste man definiera en egen kopieringskonstruktor.

 

 

//Array Main.cpp

//#define NDEBUG   //onm du inte vill ha assert med skriv #define NDEBUG

#include <cassert>

#include <iostream>

using namespace std;

 

 

class Array{

    public:

       Array(int forsta_index =1,int antal =0);

       Array(const Array & v);                  //kopieringskonstruktor

       int forsta(){return i1;}                 //första elementet

       int sista(){return i1 + ant -1;}         //sista elementet

       int langd(){return ant;}                 //längden på array

       int avlas(int index);                    //avläsa ett visst element

       void andra(int index, int varde);        //ändra ett element

    private:

        int *p;                                 //pekare till int

        const int i1;                           //första tillåtna index  

        int ant;                                //antalet

    };

 

 

 

Array::Array(int forsta_index, int antal )

: i1(forsta_index), ant(antal) //i1 är en konstant kan bara använda

                               //initieringslista

    {

 

    assert(ant>=0);             //assert för att kolla ant ej blir negativt

    p = new int[ant];

 

    }

 

 

//kopieringskonstruktor anropas vid Array vb(va); eller Array vc = va;

//anropas bara vid initieringar ej tilldelningar

Array::Array(const Array & v )

: i1(v.i1), ant(v.ant )                 //i1 och ant kopieras först  

    {                   

   

    p = new int[ant];                   //allokera ett fält int[ant]

    for(int i = 0;i< ant; i++)   

        p[i] = v.p[i];                  //kopiera en och en - det går

    } //inte att kopiera p = v.p för då kommer v.p objektet att dela

      //på samma minnes område. Vi måste kopiera hlea fältet.

//kallas för DJUP KOPIERING till skillnad från den aoutomatiska konstruktorn

//som gör en GRUND KOPIERING

Array::avlas(int index)

    {

 

    assert(index >= i1 && index <= sista());

    return p[index-1];

 

    }

 

 

void Array::andra(int index, int varde)

 

    {

   

    assert(index >= i1 && index <= sista());

    p[index - i1] = varde;

 

    }

 

 

 

 

int sum(Array& v)

    {

 

    int s =0;

    for(int i=v.forsta(); i<= v.sista(); i++)

        s += v.avlas(i);

    return s;

 

    }

 

 

void kvadrera(Array& v)

    {

   

    for(int i=v.forsta(); i<= v.sista(); i++)

        {

        int x= v.avlas(i);

        v.andra(i, x*x);

        }

    }

 

 

void main()

    {

 

    int n, x;

    cout << "Antal mätvärden?"; cin >> n;

    Array v1(1,n);

    cout << "Ange mätvärden" << endl;

 

    for(int i = 1; i<= n; i++)

    {

    cin >> x;

    v1.andra(i,x);

    }

       

    Array v2 = v1; //här används vår egen definerade kopieringskonstruktor

    kvadrera(v2);

    cout << "Summan: " << sum(v1) << endl;

    cout << "Kvadrat summan: " << sum(v2) << endl;

 

    }

 

Typomvandlingskonstruktor

En konstruktor som kan anropas med bara ett argument. Finns fler måste de ha default värden.

 

 

 

//Typomvandlingskonstruktor sid 241

 

 

#include <iostream>

using namespace std;

 

 

class RatTal{

    public:

        RatTal() :talj(0), namn(1) {}

        RatTal(int i) : talj(i), namn(1){} //har en parameter TYPOMVANDLINGS

        void skriv(){cout << talj << " " << namn << endl;} //KONSTRUKTOR

    private:

        int talj, namn;

    };

 

 

 

class Text{

    public:

        Text(int n = 0);

        Text(char * s);  //en parameter TYPOMVANDLINGSKONSTRUKTOR

        void skriv(){cout << p   << endl;}

    private:

        char *p;

        int langd;

    };

 

Text::Text(int n  ){

    langd = n;

    p = new char [langd +1];

    for(int i=0; i<langd; i++)

        p[i] = ' ';

    p[langd] ='\0';

    }

 

Text::Text(char *s ){

    langd = strlen(s);

    p = new char [langd +1];

    strcpy(p,s);

    }

 

 

void main()

    {

RatTal r1, r2(5);

 

    r1.skriv();

    r2.skriv ();

    r1 = 9;             //typomvandling från int till RatTal 

    r2=RatTal(9);

    r1.skriv();

    r2.skriv();

 

    Text t1(5), t2("typomvandlingskonstruktor");

 

    t1.skriv() ;        //skriver: 5 blanktecken

    t2.skriv() ;        //skriver: typomvandlingskonstruktor

   

    }

 

Destruktorer

~Klassnamn();

Används för att städa efter ett objekt. anropas automatiskt nr ett objekt upphör att existera.

Är alltid parameterlös. Kan ej överlagras.

Om man har allokerat minne ”on the heap” alltså med new kan man sätta delete [] pek; här.

 

Konstanta medlemsfunktioner

Medlemsfunktioner som inte gör några ändringar i det aktuella objektet anges med const i funktionsdefinitionen. resultattyp funktionsnamn(parameterlista) const;

Obs gör det för alla funktioner som inte ändras!

 

Ex:

class Klocka{

    public:

        void stall (int tim, int min, int sek);

        int avlas_tim() const {return t;}

        int avlas_min() const {return m;}

        int avlas_sek() const {return s;}

        void skriv(bool skriv_sek = true) const;

        void ticka();

    private:

        int t, m, s;

    };

 

 

Pekaren this

Alla medlemsfunktioner får en dold parameter. Denna parameter heter this och det är en pekare till det aktuella objektet. När man är inne i en medlemsfunktion skriver namnet på en medlem m så tolkar kompilatorn det som om  man hade skrivit (this->m)

I vanliga fall behöver man inte tänka på pekaren this men det finns två fall när man explicit måste använda sig av pekaren this:

När man inifrån en medlemsfunktion behöver anropa en annan funktion  som skall ha ett objekt av den aktuella klassen som parameter.

När man vill lämna det aktuella objektet – eller referens eller pekare till det som resultat från en medlemsfunktion. Detta behövs om man vill skriva medlemsfunktionen som skall kunna anropas i en enda sekvens.

 

Ex:

 

Klocka& Klocka::stall(int tim, int min, int sek)

    {

    t = tim;

    m = min;

    s = sek;

    return *this;  //en referens till Klocka

    }

 

 

Klocka& Klocka::ticka()

    {

    s = (s+1) %60;

    if(s == 0)

        {

        m = (m+1) % 60;

        if(m == 0)

            t = (t+1) % 24;

        }

    return *this; //this = det som this pekar på

    }

 

Man kanske tycker att det borde stå return this, men det är fel: Hade det däremot varit en retur typ från funktionen  som pekare till Klocka, dvs Klocka* skulle det stå reurn this

 

 

friend

I en klass funktion kan man ange att en viss funktion eller en annan klass skall vara ens vän.

class C{

friend typ f(parametrar);

friend class C2;

……

};

Funktionen f och klassen C2 får då tillgång till de private medlemmarna I C

 

Ex:

 

class Array{

    public:

       friend void kvadrera(Array& v);        //kvadrera tillgång till

       Array(int forsta_index =1,int antal =0); //privata medlemmar

       Array(const Array & v);                                       //kopieringskonstruktor

       int forsta(){return i1;}                            //första elementet

       int sista(){return i1 + ant -1;}                //sista elementet

       int langd(){return ant;}                          //längden på array

       int avlas(int index);                                //avläsa ett visst element

       void andra(int index, int varde);            //ändra ett element

    private:

        int *p;                                                    //pekare till int

        const int i1;                                            //första tillåtna index  

        int ant;                                                   //antalet

    };

 

 

Nu kan vi effektivare göra en kod för kvadrera

void kvadrera(Array& v)

    {

   

    for(int i=0 i<= v.ant i++)

        v.p[i] *= v.p[i];

 

    }

 

 

Operatorer

Funktioner med namn operatorx, där x är operator symbol. De flesta fördefinerade operatorer får överlagras för klasstyper. Kan ha en operand (unära) eller två operander (binära).

Antal operander och prioritet samma som för motsvarande fördefinierade operator. Kan konstrueras som medlemsfunktioner eller vänfunktioner (friend).

Unära operatorer har saknar parameter, binära operatorer har en parameter.

 

Binära operatorer:

Skall ha en parameter om den är en medlemsfunktion

aktuellt objekt == vänster operand

Parametern == höger operand

Varnoga med att skilja på operatorer där aktuellt objekt ändras eller inte

 

operator==

//referens för att undvika kopiera hela objektet (constant - inget får ändras)

 bool Array::operator== (const Array& v) const //binär operator

 {                              //första parametern undeförstådd

   if (ant != v.ant)            //samma längd för att bli lika       

     return false;

   for (int i=0; i<ant; i++)

     if (p[i] != v.p[i])        //samma innehåll

       return false;

   return true;

 }

 

operator+=

//vänstra operanden underförstådd. Referens till en konstant

 //resultatet skall vara en kopia av det nya värdet

 const Array& Array::operator+= (const Array& v)

 {

   assert(ant==v.ant);

   for (int i=0; i<ant; i++)

     p[i] += v.p[i];

   return *this;  //this = detta objektet, returnera som referens

 }

const Array& Array::operator+= (int d) // Heltalsoperator

 {

             for (int i=0; i<ant; i++)

               p[i] += d;

             return *this;

 }

 

operator+

Array Array::operator+ (const Array& v) const

 {

    Array temp(*this);     // Skapa kopia av detta Array-objekt

   temp += v;

   return temp; //går inte att resultattypen skall vara en referens

     } //temp existerar bara här och vi skulle få en kvardröjande pekare

 

 

 Array Array::operator+ (int d) const  // Heltalsoperator

 {

   Array temp(*this);

   temp += d;

   return temp;

 }

 

Sammanslagningsoperator (lägg till nytt element)

operator&=

const Array& Array::operator&= (const Array& v)

 {

   int *q = new int[ant+v.ant]; // Skapa nytt utrymme

   for (int i=0; i<ant; i++)

     q[i] = p[i];                          // Kopiera detta Array-objekt

   for (int j=0; j<v.ant; j++)

     q[j+ant] = v.p[j];                // Kopiera v

   delete[] p;                             // Frisläpp gammalt utrymme

   p=q;                                      // Peka på den nya utrymmet

   ant += v.ant;                         // Öka längden

   return *this;

 }

 

operator&                                (ex V3 = V1 & V2)

Array Array::operator& (const Array& v) const

 {

   Array temp(*this);     // Skapa kopia av detta Array-objekt

   temp &= v;                //använd vår tidigare operator&=

   return temp;              //returnerar kopian (ej en pekare)

 }

 

operator!=                               

bool Array::operator!= (const Array& v) const

   {

  return !((*this) == v);  //använder vår == operator

   }

 

Har man definierat en == operator är det lätt att !=, precis som < lätt blir >  osv

I filen utility finns en uppsättning färdigdefinierade mönster för relationsoperatorer och man kan tillämpa dem på vilken klass som helst. Vad som krävs är att man själv definierar == och <

 

operator<

bool Array::operator< (const Array& v) const

  {

    int n;   // skall innehålla längden av den kortaste

    if (ant < v.ant)

      n = ant;

    else

      n = v.ant;

    for (int i=0; i<n; i++)

      if (p[i] < v.p[i])

        return true;

      else if (p[i] > v.p[i])

        return false;

    return ant < v.ant;   // lika långa

  }

 

Unär operator

Skalll inte ha några parameterar om den är medlemsfunktion

aktuellt objekt == operanden

 

const Array& operator++();    //prefix ++v

Array operator++(int);            //postfix v++

Eftersom båda operatorerna är lika har man gjort ett speciellt skrivsätt.

Heltalsparametern är med bara för att markera att det är postfix varianten och

man låtsas att operatorn är binär.

 

const Array& Array::operator++ ()     // prefix ++v

 {

   return (*this) += 1;                           // Returnera nya värdet

 }

 

 Array Array::operator++ (int)               // postfix v++

 {

   Array temp(*this);                               // Skapa kopia av detta Array-objekt

   (*this) += 1;                                         // Öka detta detta Array-objekt

   return temp;                                         // Returnera gamla värdet

 }

 

operator-

Array Array::operator- () const

 {

              Array temp(*this);        // Skapa kopia av detta Array-objekt

              for (int i=0; i<ant; i++)

                temp.p[i] = -temp.p[i]; // Negera varje element

              return temp;

 }

 

 

Tilldelningsoperatorn:

I de flesta fall fungerar den automatiska tilldelningsoperatorn, men om man i en klass har någon data medlem som är en konstant eller referens fungerar det inte. Om man för att göra en djup kopiering använder en egen kopieringskonstruktor måste man och göra en tilldelningskonstruktor. vid initieringar kommer dock kopieringskonstruktorn att anropas.

 

operator=

const Array& Array::operator= (const Array& v)

 {

   if (this != &v)              // kopiering till sig själv?

   {                                   // nej

     delete [] p;                  // frigör gammalt utrymme

     ant = v.ant;

     p = new int[ant];         // allokera nytt utrymme

     for (int i=0; i<ant; i++) 

       p[i] = v.p[i];              // kopiera elementen

   }

   return *this;

 }

 

operator[]                  //lämligt att ha två – en med och en utan const

 int& Array::operator[] (int i)

 {

   assert(i >= i1 && i <= sista());

   return p[i-i1];                  // returnera en referens

 }

 

 int Array::operator[] (int i) const          //med const

 {

   assert(i >= i1 && i <= sista());

   return p[i-i1];                  // returnera en kopia

 }

 

operator()       //funktionsoperatorn kan ha godtyckligt antal parametrar

 const Array Array::operator() (int fran, int till) const

 {

   assert(fran<=till && fran>=i1 &&

          till<=sista());

   Array temp(fran, till-fran+1);     // Skapa en skiva

   for (int i=0; i < temp.ant; i++)

                temp.p[i] = p[fran-i1+i];        // Kopiera elementen

   return temp;

 }

 

friend funktioner som operand

skall ha lika många parametrar som antalet operander. Måste användas när vänsteroperanden inte tillhör den aktuella klassen

 

Array operator+ (int d, const Array& v)

 {

   return v+d;

 }

 

 std::ostream& operator<< (std::ostream& o, const Array& v)

 {

   o << '[';

   if (v.ant>0)

     o << v.p[0];

   for (int i=1; i<v.ant; i++)

                o << ", " << v.p[i];

   o << ']';

   return o;

 }

 

 std::istream& operator>> (std::istream &in, Array &v)

 {

   for (int i=0; i<v.ant; i++)

               in >> v.p[i];

   return in;

 }

 

typomvandlingsoperator

operator typ()const;

Medlemsfunktion. Inga parametrar eller resultattyp får anges. Omvandlar från den aktuella klassen till typen typ. Anropas automatiskt när typomvanling behövs

 

Ex från RatTal (rationella tal)

RatTal::operator double() const

       {

           return double(talj)/namn;

       }

 

 

 

 

//DynArray.h

#ifndef DYNARRAY_H

#define DYNARRAY_H

 

//

// Operatorerna tolkas som elementvis addition, multiplikation, etc.

//

// Operatorerna antar att arrayernas längd är lika. Detta kollas INTE

// eftersom huvudsyftet med detta klass är att demonstrera överlagring av

// operatorer. Vissa operatorer kan skrivas om och fungera bra även för

// oliklånga arrayer (== och < t.ex.) medan andra (+,-,etc) nog bör generera

// fel (kasta s.k. undantag) om arrayerlängderna inte stämmer överrens.

//

 

#include <iostream>

using namespace std;

#include <utility>               // för automatiska jämförelseoperatorer

using namespace std::rel_ops;    // för automatiska jämförelseoperatorer

 

 

class DynArray

{

 public:

  DynArray();

  DynArray(int size);

  DynArray(double *arr, int size );

  DynArray(const DynArray & arr);

  ~DynArray();

 

  int getSize() const { return bufSize; }

  void add( double d );

  void add( int num, double d = 0.0);

  void remove( int index );

 

  // Tilldelningsoperatorn

  const DynArray & operator=(const DynArray & arr);

 

  // Indexeringsoperatorn

  double & operator[](int index) {return array[index];}

  double operator[](int index) const {return array[index];}

 

  // Binära operatorer

  DynArray& operator+=(const DynArray & v);

  DynArray& operator-=(const DynArray & v);

  DynArray operator+(const DynArray & v) const;

  DynArray operator-(const DynArray & v) const;

 

  DynArray operator*(const double scale) const;

  DynArray operator*(const DynArray & arr) const;

 

  const DynArray & operator*=(const double scale);

  const DynArray & operator*=(const  DynArray & arr);

 

  bool operator==(const DynArray & arr) const;

  bool operator<(const DynArray & arr) const;

  // operatorerna !=, <=, > och >= genereras av <utility>

 

  // Unära operatorer

  DynArray operator-() const;

  operator bool() { return array != 0; } // returnerar status

  bool operator !() { return array == 0; }    // returnerar status

 

  // Funktionsanropsoperatorn

  DynArray operator() (const int lower, const int upper) const;

 

  // Vänner som operatorer

  friend DynArray operator*(const double scale, const DynArray & arr);

  friend ostream & operator<<(ostream & os, const DynArray & arr);

  friend istream & operator>>(istream & is, DynArray & arr);

 

 private:

  double * array;

  int bufSize;

};

 

#endif

 

 

//DynArray.cpp

#include "DynArray.h"

#include <iostream>

using namespace std;

 

DynArray::DynArray() : bufSize(0), array(0)

{

  cout<<"DynArray constructor"<<endl;

}

 

DynArray::DynArray(int size) : bufSize(size)

{

  cout<<"DynArray constructor: size = "<<bufSize<<endl;

  array = new double[bufSize];

  for (int i=0;i<bufSize;i++)

    array[i] = 0.0;

}

 

DynArray::DynArray(double *arr, int size ) : bufSize(size)

{

  array = new double[bufSize];

  for (int i=0;i<bufSize;i++)

    array[i] = arr[i];

}

 

// Kopieringskonstruktor

DynArray::DynArray(const DynArray & arr) : bufSize(arr.bufSize)

{

  cout<<"DynArray copy constructor"<<endl;

  array = new double[bufSize];

 

  for(int i = 0; i < bufSize; i++)

    array[i] = arr.array[i];

}

 

DynArray::~DynArray()

{

  cout<<"DynArray destructor"<<endl;

  delete[] array;

}

 

// Lägg till ett element sist

void DynArray::add( double d )

{

  double *temp = new double[bufSize+1];

  for (int i=0; i < bufSize; i++)

    temp[i] = array[i];

  temp[bufSize++] = d;

  delete[] array;

  array = temp;

}

 

void DynArray::add( int num, double d )

{

  double *temp = new double[bufSize+num];

  for (int i=0; i < bufSize; i++)

    temp[i] = array[i];

  for ( i=bufSize; i < bufSize+num; i++) 

    temp[i] = d;

  delete[] array;

  array = temp;

}

 

// Ta bort elementet i position index

void DynArray::remove( int index )

{

  double *temp = new double[bufSize-1];

  for (int src=0,dst=0; src < bufSize; src++)

    if (src!=index)     

      temp[dst++] = array[src];

  delete[] array;

  array = temp;

}

 

// Tilldelningsoperator

const DynArray & DynArray::operator=(const DynArray & arr)

{

  cout<<"DynArray assignment"<<endl;

  if (this != &arr)

    {

      bufSize = arr.bufSize;     

      delete[] array;

     

      array = new double[bufSize];

     

      for(int i = 0; i < bufSize; i++)

             array[i] = arr.array[i];

    }

  return *this;

}

 

DynArray& DynArray::operator+=(const DynArray & arr)

{

  for (int i=0; i < getSize(); i++)

    operator[](i) += arr[i];   // använder indexeringoperatorn i båda arrayerna

  // Alternativa, ekvivalenta skrivsätt:

  //  array[i] = arr[i];       // indexeringsoperatorn bara i arr

  //  array[i] = arr.array[i]; // använder ej indexeringsoperatorn

  return *this;

}

 

DynArray& DynArray::operator-=(const DynArray & arr)

{

  for (int i=0; i < getSize(); i++)

    array[i] -= arr[i];

  return *this;

}

 

DynArray DynArray::operator+(const DynArray & arr) const

{

  DynArray result(*this); // använder kopieringskonstruktorn

  return result += arr;   // använder operatorn +=

}

 

DynArray DynArray::operator-(const DynArray & arr) const

{

  DynArray result(*this); // använder kopieringskonstruktorn

  return result -= arr;   // använder operatorn -=

}

 

/* Alternativa versioner av + och - utan användning av += och -=

DynArray DynArray::operator+(const DynArray & arr) const

{

  DynArray result(getSize());

 

  for(int i = 0; i < getSize(); ++i)

      result[i] = operator[](i) + arr[i];

  return result;

}

 

DynArray DynArray::operator-(const DynArray & arr) const

{

  DynArray result(getSize());

 

  for(int i = 0; i < getSize(); ++i)

      result[i] = operator[](i) - arr[i];

  return result;

}

*/

 

const DynArray & DynArray::operator*=(const double scale)

{

  for(int i = 0; i < getSize(); ++i)

      array[i] *= scale;

  return *this;

}

 

const DynArray & DynArray::operator*=(const DynArray & arr)

{

  for(int i = 0; i < getSize(); ++i)

    array[i] *= arr[i];   

  return *this;

}

 

DynArray DynArray::operator*(const double scale) const

{

  DynArray result(getSize());

 

  for(int i = 0; i < getSize(); ++i)

    result[i] = operator[](i) * scale;  // eller result[i] = array[i]*scale;

  return result;

}

 

DynArray DynArray::operator*(const DynArray & arr) const

{

  DynArray result(getSize());

 

  for(int i = 0; i < getSize(); ++i)

    result[i] = operator[](i) * arr[i];  // eller result[i] = array[i]*arr[i];

  return result;

}

 

bool DynArray::operator==(const DynArray & arr) const

{

  for(int i = 0; i < bufSize; i++)

    if(array[i] != arr.array[i])

      return false;

  return true;

}

 

// Mindre än definieras här som att det första elementet som skiljer

// sig åt är mindre.

bool DynArray::operator<(const DynArray & arr) const

{

  for(int i = 0; i < bufSize; i++)

    if(array[i] < arr.array[i])

      return true;

  return false;

}

 

/* om vi inte inkluderade <utility>:

bool DynArray::operator!=(const DynArray & arr) const

{

  return ! ((*this) == arr);

}

*/

 

DynArray DynArray::operator-() const

{

  DynArray result(getSize());

  for(int i = 0; i < getSize(); ++i)

    result[i] = -operator[](i);

  return result;

}

 

DynArray DynArray::operator() (const int lower, const int upper) const

{

  // OBS! vi tolkar upper som elementet efter det sista som skall kopieras

  DynArray result(upper - lower);

 

  for(int i = 0; i < upper - lower; ++i)

    result[i] = operator[](lower + i);

  return result; 

}

 

// *** Friends ***

 

DynArray operator*(const double scale, const DynArray & arr)

{

  return arr * scale;

}

 

ostream & operator << (ostream & os, const DynArray & arr)

{

  if(arr.getSize() > 0)

    {

      os<<"<"<<arr[0];

      for(int i = 1; i < arr.bufSize; ++i)

                 {

               os<<" "<<arr[i];

                 }

      os<<">";

    }

  return os;

}

 

// Läsning är alltid litet krångligare än skrivning...

// Inläsningsmetoden använder en tillfällig array för läsning

// Denna kan växa efter behov.

 

istream & operator >> (istream & is, DynArray & arr)

{

  // Här ser vi ett exempel på en kanske inte alltid önskvärd

  // typkonvertering från int till DynArray

  // 8 "förvandlas" till en temporär DynArray av längden 8

  // som sedan med hjälp av DynArrays tilldelningsoperator tildelas arr

  // arr = 8;

  // Bättre att explicit tala om vad man gör:

  arr = DynArray(8);

  char c;

  is >> c; // läs bort '<'

  double value;

  int realSize = 0;

  while ( is >> value)

    {

      if (realSize== arr.bufSize) // om slut på plats

             arr.add(arr.bufSize);     // fördubbla storleken!

      arr[realSize] = value;

      realSize++;

    }

  arr.bufSize = realSize;         // vi har iofs troligen allokerat mer men...

  return is;

}

 

Statiska datamedlemmar

static typ namn; //deklaration

Definitionen läggs utanför klassdefinitionen

typ klassnamn::namn = initieringsvärde

Finns bara i en enda instans. Delas av klassens objekt.

 

Statiska medlemsfunktioner

class C {

static returtyp namn(parametrar);

};

Definieras som andra medlemsfunktioner. Får endast använda statiska datamedlemmar. Anropas inte för något speciellt objekt.

 

MALLAR (templates)

I C++ finns möjligheten att använda generiska klasser. Man skriver då en mall (template) för klassen, en så kallad klassmall och kompilatorn genererar aoutomatiskt utifrån denna mall. Man kan också konstruera generiska funktioner och man skriver då en funktionsmall.

 

 Exempel – skriv först en vanlig klass:

 

class Matris {

    public:

        Matris(int i=0, int j=0)                     //default parametrar

            : r(i), k(j), a(new double[r*k]){}  //initieringslista

        Matris(const Matris& m)                  //kopieringskonstruktor

            : a(0) {*this = m;}

        ~Matris() {delete []a;}

        int ant_rad() {return r;}                    //antal rader

        int ant_kol() {return k;}                   //antal kolumner

        Matris& operator= (const Matris&);      //tilldelningskonstruktor

        double& operator() (int i, int j);         //funktionsoperator - gör

      

    private:                                                //det möjligt med indexeringar

        double *a;                                       //pekare till fältet

        int r,k ;                                            //antal rader resp kolumn

                                          

    };

 

        Matris& Matris::operator= (const Matris& m)

            {

            if(this != &m) //om det inte är tilldelning till sig själv

                {

                r = m.r;

                k = m.k;

                delete []a;            //avallokera minnet

                a = new double[r*k];   //allokera nytt minne

                for(int i= 0; i< r*k; i++)

                    a[i] = m.a[i];     //kopiera medlem för medlem

                }

            return *this;

            }

 

          

       

        double& Matris::operator () (int i, int j){

            if(i<1 || i>r || j<1 || j>k)

                throw out_of_range("Matris::operator()");

            return a[(i-1)*k + j-1];

            }

 

Ändra till matris

 

template <class T>

class Matris {

    public:

        Matris(int i=0, int j=0)                //default parametrar

            : r(i), k(j), a(new T[r*k]){}       //initieringslista

        Matris(const Matris& m)                 //kopieringskonstruktor

            : a(0) {*this = m;}

        ~Matris() {delete []a;}

        int ant_rad() {return r;}               //antal rader

        int ant_kol() {return k;}               //antal kolumner

        Matris& operator= (const Matris&);      //tilldelningskonstruktor

        T& operator() (int i, int j);            //funktionsoperator - gör

      

    private:                                    //det möjligt med indexeringar

        T *a;                                   //pekare till fältet

        int r,k ;                               //antal rader resp kolumn

                                          

    };

        template<class T>

        Matris<T>& Matris<T>::operator= (const Matris& m)

            {

            if(this != &m) //om det inte är tilldelning till sig själv

                {

                r = m.r;

                k = m.k;

                delete []a;            //avallokera minnet

                a = new T[r*k];   //allokera nytt minne

                for(int i= 0; i< r*k; i++)

                    a[i] = m.a[i];     //kopiera medlem för medlem

                }

            return *this;

            }

 

          

         template<class T>

        T& Matris<T>::operator () (int i, int j){

            if(i<1 || i>r || j<1 || j>k)

                throw out_of_range("Matris::operator()");

            return a[(i-1)*k + j-1];

            }

     

void main()

    {

 

    Matris<int> mi(5,8);

    Matris<person> mp(3,4);

  

   

}

 

 

Klassmallar

template<class T> //klassdefinition

class C{

    returtyp f(parametrar);

    . . .

};

 

template<class T>    //definition av medlemsfunktion

returtyp C>T>::f(parametrar)

  {     }

 

T är en typparameter och används som en vanlig typ inne I klassen. Både klassdefinitionen och definitioner av medlemsfunktionerna bör placeras i inkluderingsfilen.

 

Instanser av klassen skapas när man skriver C<typnamn>

då erästts T med typnamn överallt i denna instans. Uttrycket C<typnamn> kan användas som ett vanlig klassnamn.

   

 

 

 

 

 

 

// swt.cpp

// Simple Windows Template

// Copyright (c) William H. Murray and Chris H. Pappas, 1999

 

 

 .cpp    =  Den fil du arbgetar med och skriver (source file eller källfil)

 .h      =  Header fil där du deklarer dina funktioner

 .dsp    =  Projekt filen

 .dsw    =  Arbetsminnet (Workspace)

 .ncb    =  This is the No compile Browser file. It contains information

            generated by the parser that is used by Visual Studio utilities

            such as ClassView, izardBar, and the Component Gallery. If

            the file is accidentally or deliberately deleted, it is

            automatically regenerated.

 .opt    =  Denna fil innehåller de inställningar du har gjort för

            projektet (option)

 .plg    =  Logg fil

*************  I MAPPEN DEBUG FINNS ***********

 .exe    =  Executable file

 .ilk    =  Länkfil

 .obj    =  Objektkod i maskinkod och som används till länkningen

 .pch    =  Förkompilerad header fil (jmf stdafx.obj)

 .pdb    =  Program Data Bas fil - länkning av debug program version

  vc60.idb  = Kompilerar bara det som har ändrats (vc50 kompilering utan

            projekt)

  vc60.pdb  = Samma som ovan

  */

#include <windows.h>

 //Fördeklaration av windows CALLBACK rutin  LRESULT 32 bitars typ

 //som kan delas upp i så kallad  LOW eller HIGH                            

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM); //WndProc   finns här

    char szProgName[]="ProgName";

//WinMain = själva huvudrutinen

    int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPreInst,

                            LPSTR lpszCmdLine,int nCmdShow)

//  The WinMain() function is called by Windows   

    {//Ska initiera, skapa, registrera, hantera meddelande loop

     //och terminera WM_QUIT

HWND hWnd; //handle till fönstret

MSG lpMsg; //instans meddelande loopen

WNDCLASS wcApp; //skapa applikationen

//wcApp - hur den ska se ut

 

wcApp.lpszClassName=szProgName;

wcApp.hInstance    =hInst;

wcApp.lpfnWndProc  =WndProc;

wcApp.hCursor      =LoadCursor(NULL,IDC_ARROW);

wcApp.hIcon        =0;

wcApp.lpszMenuName =0;

wcApp.hbrBackground =(HBRUSH) GetStockObject(LTGRAY_BRUSH);

wcApp.style         =CS_HREDRAW|CS_VREDRAW;

wcApp.cbClsExtra    =0;

wcApp.cbWndExtra    =0;

if (!RegisterClass (&wcApp)) //om det inte gick att registrera

return 0; //återvänd till windows

//Skapa fönstret

hWnd=CreateWindow(szProgName,"Simple Windows Template",

        WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,

        CW_USEDEFAULT,CW_USEDEFAULT,

        CW_USEDEFAULT,(HWND)NULL,(HMENU)NULL,

        hInst,(LPSTR)NULL);

 ShowWindow(hWnd,nCmdShow);

 UpdateWindow(hWnd);

//Hantera meddelande kön

 while (GetMessage(&lpMsg,0,0,0)) { //0,0,0 är filter till GetMessage

    TranslateMessage(&lpMsg);//Inmatning från tangentbord WM_CHAR mm

    DispatchMessage(&lpMsg);//Meddelande till olika ställen

    }

return(lpMsg.wParam);//avslutar om WM_QUIT sänds

}

 

LRESULT CALLBACK WndProc(HWND hWnd,UINT messg,WPARAM wParam,LPARAM lParam)

{

    HDC hdc;

    PAINTSTRUCT ps;

switch (messg)

{

case WM_PAINT:

hdc=BeginPaint(hWnd,&ps);

MoveToEx(hdc,50,60,NULL);

LineTo(hdc,500,400);

TextOut(hdc,200,100,"Draw a line",11);

ValidateRect(hWnd,NULL);

EndPaint(hWnd,&ps);

break;

case WM_DESTROY:

PostQuitMessage(0);

break;

default:

return(DefWindowProc(hWnd,messg,wParam,lParam));

break;

}

return(0);

}