c++ for java-programmerere
DESCRIPTION
C++ for Java-programmerere. Åsmund Eldhuset for TDT4102 asmunde *at* stud .ntnu.no http://folk.ntnu.no/asmunde/tdt4102-studasskurs-2009.ppt. Forutsetninger. Du er noenlunde komfortabel med Java Du kjenner følgende konsepter innen objektorientert programmering: Klasser Innkapsling Arv - PowerPoint PPT PresentationTRANSCRIPT
C++ for Java-programmerere
Åsmund Eldhusetfor TDT4102
asmunde *at* stud.ntnu.nohttp://folk.ntnu.no/asmunde/tdt4102-studasskurs-2009.ppt
Forutsetninger
Du er noenlunde komfortabel med Java Du kjenner følgende konsepter innen
objektorientert programmering: Klasser Innkapsling Arv Polymorfi Grensesnitt (interfaces)
Litt historie
C ble utviklet på 70-tallet av Brian W. Kernighan og Dennis M. Ritchie
Designet for systemprogrammering under UNIX C++ ble utviklet på 80-tallet av Bjarne Stroustrup Bygger på C; første utgave het "C with classes" Hentet mange ideer fra norskutviklede Simula
(verdens første objektorienterte språk) Både C og C++ er åpne og ISO-standardiserte
Argumenter for C++
Raskere enn Java Java kjøres av en Virtual Machine C++ kompileres til maskinkode
Gir nærkontakt med systemet Innfallsport til C, som er enda bedre egnet til system-
programmering (operativsystemer, mikrokontrollere etc.)
Du kan gjøre ALT som er mulig å gjøre med datamaskinen
Ett av de mest utbredte programmeringsspråkene; mange eksisterende systemer er skrevet i C++
Mange ferdigskrevne biblioteker Nerdefaktor ;-)
Argumenter mot C++
Mindre nybegynnervennlig Lett å skyte seg selv så til de grader i foten Uforsiktighet kan føre til obskure
minnelekkasjer Portabiliteten varierer med hva man foretar
seg Utvikling tar generelt sett lengre tid enn med
Java og C#
Når bruke C++?
Når du trenger rå hastighet (spill, grafikk, tungregning, algoritmekonkurranser)
Når du driver systemprogrammering Når du arbeider med eksisterende C++-
systemer Når du har lyst til å leke deg med
programmering
C++ vs. Java
Java Proprietært (Sun) Garbage collection Kjøres av en VM Samme kompilerte
kode kan kjøres overalt Bruker nesten samme
syntaks som C++
C++ Åpent Manuell
minnebehandling Kompileres til
maskinkode Må rekompileres for
hvert nye system; koden kan måtte endres
Kompilatorer og IDE'er Kompilator oversetter koden til maskinkode IDE = Integrated Development Environment
(kombinerer editor, kompilator og debugger) Linux:
Kompilator: gcc / g++ Debugger: gdb Editor: det du foretrekker
Windows: Microsoft Visual Studio
(http://www.microsoft.com/express/vc) Bloodshed Dev-C++
(http://www.bloodshed.net/devcpp.html)
Bruk av g++
Kompilering: g++ kildefil Kjøring: ./a.out Kompilere flere filer: g++ kilde1 kilde2 ...
Endre navnet til outputfilen:g++ -o outputfil kildefil./outputfil
Skyte seg selv i foten:g++ -o kildefil kildefil(sletter kildekoden din)
Minimalt program
int main() { return 0;}
Vi legger merke til: Typen til main() er int, ikke void Ingen String [] args (skal programmet ta imot
argumenter, skriv int argc, char * argv []) main() er ikke public static
og står ikke inni noen klasse
Del I: Grunnleggende C++
Hello World
// Dette er et Hello World-program
#include <iostream>
using namespace std;
int main() { cout << "Hello World!" << endl; return 0;}
Hello World
Kommentarer lages med // eller /* */ cout << x << endl; tilsvarer System.out.println(x);
#include minner om import, men fungerer ved å "lime inn" en fil (mer om dette senere)
iostream er et bibliotek som inneholder IO-støtte (f.eks. cout)
using namespace minner også om import. Uten dette måtte vi skrive std::cout og std::endl, fordi cout og endl tilhører et namespace (tilsv. en pakke) som heter std.
Man kan ha funksjoner utenfor klasser; main() skal alltid være en slik funksjon
Input og output
cout << x; skriver data til skjermen cout << endl; skriver et linjeskift cin >> x; leser data fra tastaturet cin merker hvilken datatype variablene har cin og cout kan "cascade"s:cout << x << y << z; (skriver ut dataene uten mellomrom mellom)cin >> x >> y >> z; (leser først inn i x, så i y, så i z)
Variabler Variabler lages og brukes på samme måte
som i Java C++ har følgende primitive datatyper:
bool (tilsvarer boolean) char (tilsvarer byte og til en viss grad char) short int long float double
unsigned kan brukes foran heltallstypene Funksjoner kan også ha void som type
If/else, for, while
... fungerer på samme måte som i Java! Kun én forskjell: betingelser i if/else og while
kan være heltall (0 blir false, alt annet blir true)
int x, y;cin >> x >> y;if (y) cout << x / y << endl;else cout << "Nevneren er 0!" << endl;
Deklarasjon av funksjoner
Før en funksjon brukes, må kompilatoren vite at funksjonen eksisterer
Dette kan gjøres på to måter: Funksjonen kan allerede være definert (dvs. at
funksjonskoden står lenger oppe i kodefilen) Definisjonen kan finnes i en annen fil, og
funksjonen kan deklareres (dvs. at man bare skriver metodenavnet)
Eksempel: funksjonenint square(int n) { return n * n; }kan deklareres slik:int square(int);
Biblioteker og headerfiler C++-kompilatoren kompilerer én fil av gangen
uavhengig av alle de andre Biblioteksfunksjonene ligger i ferdigkompilerte
filer Headerfiler inneholder deklarasjoner som
forteller hvordan biblioteksfunksjonene ser ut Hvis f.eks. kompilatoren ser int square(int);,
stoler den på at det finnes en slik funksjon. Den kompilerer koden som bruker square() og prøver etterpå å koble inn square() sin egen kode
Sammenkoblingsprogrammet kalles for en linker, og er som regel en del av kompilatoren
Biblioteker og headerfiler
Man kan selv lage prosjekter som består av flere kodefiler Koden deles opp i kodefiler (.cpp) og headerfiler
(.h) Headerfilene inneholder deklarasjoner (navn og
parameterlister for metoder og klasser) Kodefilene inneholder definisjoner (den faktiske
implementasjonen / koden) #include "limer inn" koden fra en fil, og skal bare
brukes for å inkludere headere
Del II: Pekere
Pekere
En variabel som inneholder en minneadresse Bruk * i deklarasjoner for å lage
"peker-til-datatype" Bruk & for å finne adressen til en variabel Bruk * for å dereferere en peker (lese innholdet i
adressen det pekes til) C++ bruker NULL i stedet for null int a = 42;int * p = NULL;p = &a;cout << p << endl;cout << *p << endl;
p42a
0x32p
42a
0x04 0x32
p q
Triksing med pekere
int a = 3;int * p, * q;p = &a;q = &a;*p = 42;cout << a << endl;cout << *q << endl;
3a42
Peker-til-peker-til...
int a, * p, ** q, *** r;a = 42;p = &a;q = &p;r = &q; cout << r << endl;cout << *r << endl;cout << **r << endl;cout << ***r << endl;
q
p
42a
r
Funksjonsargumenter Alle argumenter sendes som kopi Følgende gir dermed ikke det tenkte resultatet:void swap(int a, int b) { int temp = a; a = b; b = temp;}
Vi sender pekere i stedet, for da får vi modifisert dataene gjennom pekerne:void swap(int * a, int * b) { int temp = *a; *a = *b; *b = temp;}
Sistnevnte funksjon må kalles slik: swap(&a, &b)
Referanser
Et tredje alternativ er å bruke referanser En referanse er en mellomting mellom peker
og "rådata" Er ikke en kopi av dataene, så endring av en
referanse fører til endring av de originale dataene Kan ikke være NULL Aksesseres som om det var rådata
void swap(int & a, int & b) { int temp = a; a = b; b = temp;}
Kalles slik: swap(a, b)
Arrays
Et array er bare et sammenhengende minneområde av samme datatype
En peker kan derfor brukes til å peke til starten av et array
Arrays lages slik:int * array = new int [4];array
Arrays
Arrays er 0-indekserte og aksesseres som i Java:array[2] = array[1] + array[0];
Bak kulissene foregår oppslag på array[i] slik: Adressen i array leses Størrelsen til datatypen som array peker til
ganges med i og adderes til adressen for å finne hvor dataene ligger
array
4 bytes
0x32 0x36 0x40 0x44
0x32
Arrays
Arrays vet ikke hvor store de er, og du får ingen exception hvis du går utenfor grensene int * array = new int [8];for (int i = -1; i <= 8; ++ i)
cout << array[i] << endl; Ingen feilmelding Du får ut data Programmet kan krasje noen ganger, og fortsette
andre ganger Etter bruk må et array slettes:delete [] array;
Flerdimensjonale arrays
int ** array = new int * [3];for (int i = 0; i < 3; ++ i) array[i] = new int [4];
array
Del III: Objektorientering og minnebehandling
Klassedeklarasjoner Klasser i C++ kan ikke være public/private Deklarasjon og definisjon bør skilles Deklarasjonen avsluttes med et semikolon Constructors fungerer som i Java Deklarasjon:class Person { Person(std::string name, int age); void presentYourself(); std::string name; int age;};
Klassedefinisjoner this er en peker, og man bruker -> for å
lese medlemmer via pekere Person::Person(string name, int age) { this->name = name; this->age = age;}
void Person::presentYourself() { cout << "Hei, jeg heter " << name << " og er " << age << " år gammel." << endl;}
Innkapsling
Tre nivåer: public, protected, private public og private er det samme som i Java Siden C++ ikke har pakker, finnes ikke
package/default visibility, og protected gir synlighet bare for subklassene
I stedet for å sette modifikatoren foran hver variabel/funksjon, setter man den som "overskrift"
Innkapsling
class Person {public: Person(std::string name, int age); void presentYourself();private: std::string name; int age;};
Objekter Man har både objektvariabler og objektpekere
Objektvariabler inneholder selve objektet, og oppfører seg som om det var en variabel av primitiv datatype – forsvinner automatisk når funksjonen avsluttes
Objektpekere oppførerer seg som Java sine objektvariabler – må allokeres og deallokeres
. brukes på objektvariabler, og -> på objektpekere Objektvariabler:Person p("Aasmund", 20);p.presentYourself();
Objektpekere:Person * p = new Person("Aasmund", 20);p->presentYourself();delete p;
Arv Tre typer arv: public, protected og private
Vi skal bare se på public, som tilsvarer Java sin type arv
C++ har ikke noe Object som alle klasser arver implisitt (du kan lage et selv hvis du vil, men det vil bare funke for dine egne klasser, ikke de innebygde)
C++ støtter multiple inheritance, dvs. at en klasse kan arve fra flere klasser
Java: class Professor extends PersonC++: class Professor : public Person
Virtuelle funksjoner
Hvis du har følgende i Java:Person p = new Professor();p.presentYourself();er det Subclass sin versjon av someFunction() som kjøres
For å få til dette i C++ må man sette virtual foran funksjonsnavnet
Ikke-virtuelle funksjonskall bestemmes ved kompileringstid ut i fra pekertypen
Virtuelle funksjonskall bestemmes ved kjøretid ut fra den egentlige typen til objektet
Abstrakte klasser og funksjoner
Abstrakte funksjoner kalles for "pure virtual" C++ har ikke abstract Sett = 0 etter en funksjon for å gjøre den
abstrakt:int someAbstractFunction(int x) = 0;
Klasser som inneholder "pure virtual"-funksjoner blir automatisk abstrakte (selv hvis de inneholder vanlige funksjoner også)
Abstrakte klasser og funksjoner Java:public abstract class BankAccount { private int balance; public abstract void deposit(int);}
C++:class BankAccount {public: void deposit(int) = 0;private: int balance;};
Abstrakte klasser og funksjoner
Abstrakte klasser kan ikke instansieres new BankAccount() er ikke tillatt
Subklasser som ikke implementerer alle "pure virtual"-funksjoner blir også abstrakte
class SavingsAccount() : public BankAccount {public: void deposit(int amount) { this->balance += amount - 100; }};
Interfaces
C++ har ikke interfaces, men variabelløse, abstrakte klasser gjør samme nytten
Java:public interface IRobberyVictim { void getRobbed(int amount);}
C++:class IRobberyVictim {public: virtual void getRobbed(int amount) = 0;};
Interfaces
Java:public class Person implements RobberyVictim
C++:class Person : public RobberyVictim
Arrays med objekter Primitive typer:int * intArray = new int [4];
Objekter:Car * carArray = new Car [4];
Objektpekere:Car ** carPointerArray = new Car * [4];for (int i = 0; i < 4; ++ i) carPointerArray[i] = new Car();
Arrays med objektera
a[0] a[1] a[2] a[3]
car
car[0] car[1] car[2] car[3]
Arrays med objektercp
cp[0] cp[1] cp[2] cp[3]
*cp[0]
*cp[1]
*cp[2]
*cp[3]
Minnebehandling C++ har ingen garbage collector Du er selv ansvarlig for å frigi minne du ikke
trenger lenger Verktøy for dette: delete, delete [],
destructors Regler for trygg minnebehandling:
Ta alltid vare på resultatet fra new Hver gang du skriver new, husk å plassere en delete på et passende sted
Et objekt som new'er noe bør vanligvis også delete det (bruk destructors)
Destructors
Klasser kan definere en destructor (bare én, uten parametre), som vil kalles når objektet destrueres (enten med delete eller når en automatisk (dvs. lokal) variabel går ut av scope)
Syntaks:class MyClass {public: ~MyClass();};
MyClass::~MyClass() { ... }
delete og delete [] delete frigir minne for et enkelt objekt/primitiv type:int * a = new int;delete a;Car * c = new Car();delete c;
Hvis delete kalles på en objektpeker, kaller den destructoren til objektet før minnet frigis
delete [] frigir minne for et array Bruk aldri delete på noe du lagde med new [], og
bruk ALDRI delete [] på noe du lagde med new For de som kan C: Bruk ALDRI free() på noe du
lagde med new eller delete på noe du lagde med malloc()
delete og delete []
delete [] på et objektarray kaller destructors:
Car * carArray = new Car [4];delete [] carArray;
delete [] på et objektpekerarray kaller ikke destructors, så det må deallokeres slik:Car ** carPointerArray = new Car * [4];for (int i = 0; i < 4; ++ i) carPointerArray[i] = new Car();for (int i = 0; i < 4; ++ i) delete carPointerArray[i];delete [] carPointerArray;
Templates
Tilsvarer generics i Java. Lar deg skrive generisk kode som fungerer med flere datatyper
template<typename T>void swap(T * a, T * b) { T temp; temp = *a; *a = *b; *b = temp;}
Hver gang du bruker en template-funksjon på en bestemt datatype, lages en ny utgave av koden for funksjonen (ulikt hvordan det er implementert i Java)
Operator overloading Dette gjør at du kan få operatorer til å fungere på
egendefinerte klasser F.eks. kan man ha en vektor-klasse, og så definere + til å
bety vektoraddisjon (når + står mellom to vektorer), - til å bety vektorsubtraksjon og * til å bety prikkprodukt
Kan misbrukes – vær påpasselig med å bare definere meningsfylte og intuitive operasjoner (ikke bruk + til subtraksjon)
En operator kan overloades som: En medlemsfunksjon (gir operatoren full tilgang til objektdataene,
men venstre operand må være et objekt av samme type) Som en friend-funksjon (gir også full tilgang) En frittstående funksjon (gir bare tilgang vha. getters og setters)
Noen nyttige linker
C++ FAQ Lite: http://www.parashift.com/c++-faq-lite
C++ FQA Lite:http://yosefk.com/c++fqa/
STL-dokumentasjon (Standard Template Library):http://www.sgi.com/tech/stl/
En av mange C++-tutorials (det er bare å søke etter flere): http://www.cplusplus.com/doc/tutorial/
For de avanserte som vil prøve seg på grafikkprogrammering: http://nehe.gamedev.net/
De klassiske vitsene om selvskudd i foten:http://www-users.cs.york.ac.uk/susan/joke/foot.htm