Introduktion till C++
Förord
Det här är första delen i vad jag hoppas ska bli en serie av artiklar om C++. Jag kommer i den här artikelserien att i största möjliga mån använda standard C++ som kanske inte alltid är exakt vad som används i VC++ men oftast är det inga problem. C++ är ett objektorienterat språk som utvecklats ur C. Medans C är ett funktionellt språk som använder sig av funktioner för att gruppera arbete använder man i C++ klasser som representarar de grundläggande delar man bör finna när man gör en objektorienterad analys av sitt problem. Det där låter ju luddigt värre men räds icke, det klarnar under resans gång.Innehåll
»»
»
Relaterade artiklar
» Kontrollstrukturer i C++C++ är objektorienterat vilket innebär att de data man använder är klasser, för att visa detta går vi rakt på ett exempel som jag senare ska förklara. Observera att all text på en rad efter dubbla snedstreck (//) är en kommentar.
Ovanstående exempel är förvisso möjligt att kompilera och köra i en C++ kompilator men det är inte mycket som är objektorienterat i programmets uppbyggnad. Jag har ändå med exemplet för att visa hur ett mycket enkelt program ser ut. De två första raderna lämnar vi tills vidare. Acceptera bara att de måste vara med för att kunna köra programmet.
Ett C++ program består av satser (statements) som avslutas med semikolon (;). Flera satser kan grupperas med "måsvingar" {}. Alla skalprogram (*nix shell / DOS mfl) startar sin exekverning (körning) i funktionen main. Funktioner skrivs i C++ precis som i C (och metoder Java) som
main tar tydligen en del argument som ser ganska konstiga ut. Detta behöver vi inte bry oss om än, det kommer först då vi vill skicka parametrar till vårt program. (C-programmerare känner naturligtvis igen sig)
På den första raden i main anropas objektet cout som hanterar utskriftsströmmar med strängen "Detta är mitt första C++ program". Strängliteraler (hårdkodade strängar) skrivs inom citationstecken precis som i C och Java.
Syntaxen för utskriften ser lite snårig ut och beror på att cout överlagrar << operatorn. Mer om detta långt senare. Slutligen returnerar vi 0 vilket innebär att programmet avslutas normalt. Detta är ett sätt att tala om för det skal som starade programmet att allt har gårr bra. Tidigare var main inte tvunget att returnera något men i standard C++ returneras ALLTID en int, dvs ett heltal.
Det finns ett flertal inbyggda datatyper i C++ och vi börjar med några få. Till skillnad från Java är inte antalet bitar garanterat utan kan variera mellan olika implementationer.
Alla inbyggda typer kan även finnas i arrayer. En array är helt enkelt ett flertal datafält i rad
En array betecknas alltså med hakparenteser och används oftast för att spara sekvenser. Vi hade kunnat skapa tolv stycken int:ar (int january = 31; int february = 28;) men det känns krångligt. För att komma åt något i en array används alltså hakparentes men i exemplet skrev jag ut att mars har så många dagar som element nummer två, hur kan det stämma när alla vet att mars är månad nummer 3.
För den som har programmerat förrut är detta inget nytt. Arrayer är nollräknade, dvs deras index börjar med 0 och går till deras storlek - 1 (i vårt fall 0 till 11). I C++ (och C) finns dessutom pekare och referenser men vi väntar en stund även med dessa.
Nu till det viktigaste, klasser! En klass är en logisk indelning av data och funktioner att bearbeta dessa data med. Det förklaras nog enklast med ett exempel. Det här är trots allt inte en kurs i objektorienterad design. När man skapar en klass börjar man med att specificera dess gränssnitt (interface) i en header fil.
I filen Car.h
Även här kan man till en början bortse från de rader som börjar med #. Sådant kommer att klarna senare.
Här berättar vi att en bil har vissa egenskaper (toppfart och tankvolym) samt kan utföra vissa operationer (tankas och köras). Men vi säger ingenting om HUR det går till när vi tankar eller kör, detta finns i implementationsfilen. Det finns en tanke bakom det här och den är att man kan ändra hur man kodat någonting utan att ändra i headern. Något som kan underlätta massor vid exempelvis optimering av stora projekt. Innan jag förklarar mer går vi på implementationen i filen Car.cpp
Detta beskriver alltså vad som händer när man tankar respektive kör bilen. Notera att det finns funktioner som tar hand om de specialfall som blir när man försöker tanka för mycket eller när soppan tar slut när man är ute och kör. Det är en av fördelarna med objektorienterad design. Man gömmer datat så att det bara kan ändras på det sätt du har tänkt dig. När jag beskriver en funktion i implementationsfilen talar jag om till vilken klass den hör med räckviddsoperatorn (::). Det finns två speciella funktioner. Den som heter Car och den som heter ~Car.
Den första är konstruktorn och anropas varje gång vi skapar en ny bil. Där ställer vi in sånt som gäller från början. Den andra är destruktorn och anropas när vår bil förstörs (i programmet, inte på skroten). I vårt fall behöver vi inte göra någon upprensning så den kan vara tom. Slutligen ska vi använda vår fina lilla klass.
Här skapar vi en variabel, objektet myCar som är av typen (klassen) Car. Sen tankar vi den med 36 liter och därefter kör vi 20 kilometer i 90km/h. Här känns koden ganska självförklarande. Försök alltid att skapa funktionsnamn som beskriver vad funktionen gör. Experimentera gärna med koden och testa att skapa fler bilar och tanka och kör dem. I nästa kurs tänkte jag fortsätta lite med bilen och bygga ut det hela.
Per studerar datateknik på KTH och arbetar för tillfället på Jadestone Group. Jadestone är ett företag som tillverkar dataspel, främst onlinespel och spel för mobiltelefon. Det kanske mest kända är Football Manager som drivs i samarbete med Canal+ och Aftonbladet.
#include // För att få tillgång till cout
using namespace std; // Ger åtkomst till standardnamnrymden
int main(int argc, char* argv[]) // Här börjar körningen
{
cout << "Detta är mitt första C++ program" << endl;
return 0;
}
Ovanstående exempel är förvisso möjligt att kompilera och köra i en C++ kompilator men det är inte mycket som är objektorienterat i programmets uppbyggnad. Jag har ändå med exemplet för att visa hur ett mycket enkelt program ser ut. De två första raderna lämnar vi tills vidare. Acceptera bara att de måste vara med för att kunna köra programmet.
Ett C++ program består av satser (statements) som avslutas med semikolon (;). Flera satser kan grupperas med "måsvingar" {}. Alla skalprogram (*nix shell / DOS mfl) startar sin exekverning (körning) i funktionen main. Funktioner skrivs i C++ precis som i C (och metoder Java) som
returTyp metodNamn(argumentTyp1 arg1, argumentTyp2 arg2)
{
//funktionskropp
}
main tar tydligen en del argument som ser ganska konstiga ut. Detta behöver vi inte bry oss om än, det kommer först då vi vill skicka parametrar till vårt program. (C-programmerare känner naturligtvis igen sig)
På den första raden i main anropas objektet cout som hanterar utskriftsströmmar med strängen "Detta är mitt första C++ program". Strängliteraler (hårdkodade strängar) skrivs inom citationstecken precis som i C och Java.
Syntaxen för utskriften ser lite snårig ut och beror på att cout överlagrar << operatorn. Mer om detta långt senare. Slutligen returnerar vi 0 vilket innebär att programmet avslutas normalt. Detta är ett sätt att tala om för det skal som starade programmet att allt har gårr bra. Tidigare var main inte tvunget att returnera något men i standard C++ returneras ALLTID en int, dvs ett heltal.
Detta leder oss fram till C++ datatyper.
Det finns ett flertal inbyggda datatyper i C++ och vi börjar med några få. Till skillnad från Java är inte antalet bitar garanterat utan kan variera mellan olika implementationer.
namn | beskrivning | exempel på literal |
---|---|---|
int | ett heltal | 30 |
float | ett flyttal (decimaltal) | 42.5F |
double | ett flyttal med dubbel noggranhet | 36.34L |
bool | ett boolskt (sant/falskt) värde | true |
char | ett tecken | 'a' |
Alla inbyggda typer kan även finnas i arrayer. En array är helt enkelt ett flertal datafält i rad
int daysInMonth[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
cout << "Antal dagar i mars är " << daysInMonth[2] << endl;
En array betecknas alltså med hakparenteser och används oftast för att spara sekvenser. Vi hade kunnat skapa tolv stycken int:ar (int january = 31; int february = 28;) men det känns krångligt. För att komma åt något i en array används alltså hakparentes men i exemplet skrev jag ut att mars har så många dagar som element nummer två, hur kan det stämma när alla vet att mars är månad nummer 3.
För den som har programmerat förrut är detta inget nytt. Arrayer är nollräknade, dvs deras index börjar med 0 och går till deras storlek - 1 (i vårt fall 0 till 11). I C++ (och C) finns dessutom pekare och referenser men vi väntar en stund även med dessa.
Klasser
Nu till det viktigaste, klasser! En klass är en logisk indelning av data och funktioner att bearbeta dessa data med. Det förklaras nog enklast med ett exempel. Det här är trots allt inte en kurs i objektorienterad design. När man skapar en klass börjar man med att specificera dess gränssnitt (interface) i en header fil.
I filen Car.h
#ifndef _CAR_H_
#define _CAR_H_
class Car
{
public:
Car(int theTopSpeed, double theGasTankVolume, double useGas);
virtual ~Car();
void addGas(double amount);
double drive(int speed, int distance);
double getGasInTank();
private:
int topSpeed;
double gasTankVolume;
double gasInTank;
double gasUsage;
};
#endif
Även här kan man till en början bortse från de rader som börjar med #. Sådant kommer att klarna senare.
Här berättar vi att en bil har vissa egenskaper (toppfart och tankvolym) samt kan utföra vissa operationer (tankas och köras). Men vi säger ingenting om HUR det går till när vi tankar eller kör, detta finns i implementationsfilen. Det finns en tanke bakom det här och den är att man kan ändra hur man kodat någonting utan att ändra i headern. Något som kan underlätta massor vid exempelvis optimering av stora projekt. Innan jag förklarar mer går vi på implementationen i filen Car.cpp
#include
#include "Car.h"
using namespace std;
Car::Car(int theTopSpeed, double theGasTankVolume, double useGas)
{
topSpeed = theTopSpeed;
gasTankVolume = theGasTankVolume;
gasUsage = useGas;
gasInTank = 0;
}
Car::~Car()
{
}
void Car::addGas(double amount)
{
gasInTank += amount; // kortform av gasInTank = gasInTank + amount;
if(gasInTank > gasTankVolume)
{
cout << "Det blev " << gasInTank - gasTankVolume << " liter över." << endl;
gasInTank = gasTankVolume;
}
}
double Car::drive(int speed,int distance)
{
if (speed > topSpeed)
{
cout << "Kan inte köra i " << speed << endl;
speed = topSpeed;
}
int traveledDistance = distance;
if(distance*gasUsage > gasInTank)
{
cout << "Soppan räcker inte till " << distance << " km" << endl;
traveledDistance = gasInTank / gasUsage;
cout << "Kör " << traveledDistance << " km istället." << endl;
gasInTank = 0;
}
else
{
gasInTank -= traveledDistance * gasUsage;
}
return (double) traveledDistance / speed;
}
double Car::getGasInTank()
{
return gasInTank;
}
Detta beskriver alltså vad som händer när man tankar respektive kör bilen. Notera att det finns funktioner som tar hand om de specialfall som blir när man försöker tanka för mycket eller när soppan tar slut när man är ute och kör. Det är en av fördelarna med objektorienterad design. Man gömmer datat så att det bara kan ändras på det sätt du har tänkt dig. När jag beskriver en funktion i implementationsfilen talar jag om till vilken klass den hör med räckviddsoperatorn (::). Det finns två speciella funktioner. Den som heter Car och den som heter ~Car.
Den första är konstruktorn och anropas varje gång vi skapar en ny bil. Där ställer vi in sånt som gäller från början. Den andra är destruktorn och anropas när vår bil förstörs (i programmet, inte på skroten). I vårt fall behöver vi inte göra någon upprensning så den kan vara tom. Slutligen ska vi använda vår fina lilla klass.
#include
#include "Car.h"
using std::cout;
int main(int argc, char* argv[])
{
Car myCar(150,60.0L,0.09L);
myCar.addGas(36L);
double time1 = myCar.drive(90,20);
cout << "Det tog " << time1 << " timmar att köra 20 kilometer i 90km/h" << endl;
cout << "Sen finns det " << myCar.getGasInTank() << " liter kvar i tanken." << endl;
return 0;
}
Här skapar vi en variabel, objektet myCar som är av typen (klassen) Car. Sen tankar vi den med 36 liter och därefter kör vi 20 kilometer i 90km/h. Här känns koden ganska självförklarande. Försök alltid att skapa funktionsnamn som beskriver vad funktionen gör. Experimentera gärna med koden och testa att skapa fler bilar och tanka och kör dem. I nästa kurs tänkte jag fortsätta lite med bilen och bygga ut det hela.
Kristian Ribberheim
Det skapar merintresse