Upload
others
View
7
Download
0
Embed Size (px)
Citation preview
1 Vad gjorde vi förra gången?FelhanteringOperatorerTypkonvertering
2 Grundläggande om pekare3 New4 Destruktorer5 Composition
2 / 52
Dagens föreläsning
1. Pekare
‚ new
‚ delete
‚ avreferering
‚ adress
‚ nullptr
2. Objektorientering
‚ Composition
‚ Nästlad klass
1 Vad gjorde vi förra gången?FelhanteringOperatorerTypkonvertering
2 Grundläggande om pekare3 New4 Destruktorer5 Composition
4 / 52
Vad gjorde vi förra gången
Kom ihåg att ni alltid kan gå tillbaka till förra föreläsningenoch se slides i sin helhet.
‚ Felhantering‚ Operatorer
‚ binära‚ unära‚ interna‚ externa
‚ Typkonvertering‚ static_cast‚ operatorer‚ konstruktorer
5 / 52
Felhantering i c++
‚ Testar att göra övre blocket‚ Vid fel (en throw) hoppa till ett
av catch‐blocken‚ Fel kastas upp en nivå i
programmet
try //Försök göra{
}//Fånga exceptioncatch(logic_error& e){
}catch(...){
}
6 / 52
Att tänka på
‚ try är i princip lika snabbt som vilken annan kod somhelst
‚ Exceptions är VÄLDIGT långsamma när du kastar dem
‚ Använd endast i exceptionella situationer
‚ Använd INTE exceptions som en styrstruktur
‚ Mycket långsammare
‚ Dåligt praxis
7 / 52
Binära operatorer
//Exempelc1 + c2;c3 = c1;cout << c3;
//Vad C++-kompilatorn "ser"c1.operator+(c2);c3.operator=(c1);cout.operator<<(c3);
class Complex{public:Complex operator+(Complex const& rhs) const;Complex& operator=(Complex const& rhs);//...
};std::ostream& operator<<(std::ostream& lhs,
Complex const& rhs);
8 / 52
Unära operatorer
Har 1 operand. Vår klass är den operanden.
//Exempelc1++; //post++c1; //pre--c1; //prec1--; //post-c1; //???//Hur c++ ser detc1.operator++(int{}); //?c1.operator++();c1.operator--();c1.operator--(int{}); //?c1.operator-();
//Objektet är vänstersidan//I Complex.hclass Complex{public://...Complex& operator++();Complex operator++(int);Complex& operator--();Complex operator--(int);Complex& operator-();//...
};
postinkrement är lite av ett fulhack...
9 / 52
Typomvandling
‚ Att omvandla en typ till en annan
‚ Exempelvis göra om en int till en double
‚ Varför!
‚ Hur?
10 / 52
static cast
‚ Kontrolleras compile time
‚ Krävs att objektet vet hur det konverteras till typeneller visa versa
string cs1 = static_cast<string>( Complex{1, 3} );Complex c{1, 3};string cs2 = static_cast<string>( c );
‚ Hur kan vi se till att Complex vet hur den skallkonverteras till string?
11 / 52
Hur vet klassen?
Genom att lägga till den operatorn i klassen. Objektet vethur den kan konverteras till målet
//Unary operator//MedlemsfunktionComplex::operator string(){return to_string();
}
class Complex{//...operator string();operator int();//...
}
Observera:
‚ Ingen returtyp
‚ Fungerar för andra typer
12 / 52
Typkonverterande konstruktorer
Målet vet hur objektet kan konverteras till sig
‚ konstruktorn sköterkonvertering från en annan typtill din typ
//h-filclass Complex{//...// Konstruktor som tar en parameter av typenComplex(std::string const& str);//...
}
1 Vad gjorde vi förra gången?FelhanteringOperatorerTypkonvertering
2 Grundläggande om pekare3 New4 Destruktorer5 Composition
14 / 52
Minne
‚ Datorns minne löper från 0‐N‚ N = minnetsstorlek ‐ 1‚ Består av bytes‚ Siffran i intervallet är platsen,
adressen‚ 1 megabyte är 0 till 220‐1‚ Vi kan visualisera minnet
15 / 52
Vad har en adress?
‚ Allt vi lägger i minnet har enadress
‚ Vanligtvis använder vi variablerför att komma åt den biten avminne
‚ Men vi kan också lagra ochmanipulera adresser
// Ger oss en int-stor bit av minnet// Vi kan komma åt minnet med variabelnint var{10};// Ger oss en char-stor bit av minnet// -||-char var2{'h'};
16 / 52
Lagra adress
// Vad händer?#include <iostream>
using namespace std;
int main(){
int var{};int* ptr{};cout << ptr << endl;
}
17 / 52
Lagra adress
// Vad händer?#include <iostream>
using namespace std;
int main(){
int var{17};int* ptr{17};cout << ptr << endl;
}
18 / 52
Lagra adress
// Vad händer?#include <iostream>
using namespace std;
int main(){
int var{17};int* ptr{var};cout << ptr << endl;
}
19 / 52
Lagra adress
// Vad händer?#include <iostream>
using namespace std;
int main(){
int var{17};int* ptr{&var};cout << ptr << endl;
}
20 / 52
Avreferera en adress
#include <iostream>
using namespace std;
int main(){
int var{17};int* ptr{&var};cout << *ptr << endl;// ^^^^// avreferering med * operatorn
}
21 / 52
Nullptr
int main(){
int* ptri{nullptr};cout << ptri << endl;
}
int main(){
int* ptri{nullptr};cout << *ptri << endl;
}
0
Segmentation fault
nullptr, inte 0 eller NULL!
22 / 52
sizeof
Storleken i chars (bytes), är en operator Kontroll av storlekenpå ett heltal och en adress
#include <iostream>
using namespace std;
int main(){
int var{17};int* ptr{&var};cout << sizeof(var) << endl;cout << sizeof(ptr) << endl;
}
23 / 52
sizeof
Kontroll av storleken på två (samma) heltal
#include <iostream>
using namespace std;
int main(){
int var{17};int* ptr{&var};cout << sizeof(var) << endl;cout << sizeof(*ptr) << endl;
}
24 / 52
sizeof
Kontroll av storleken på en sträng och en adress
#include <iostream>
using namespace std;
int main(){
string var{"12345678901234567890"};string* ptr{&var};cout << sizeof(var) << endl;cout << sizeof(ptr) << endl;
}
25 / 52
sizeof
Kontroll av storleken på två (samma) strängar
#include <iostream>
using namespace std;
int main(){
string var{"12345678901234567890"};string* ptr{&var};cout << sizeof(var) << endl;cout << sizeof(*ptr) << endl;
}
26 / 52
Stjärna och Ampersang
Unära operatorn “Stjärna” *
‚ I uttryck framför pekare: Avreferera (gå till adress)
‚ I deklarationer: Skapa adressvariabel (pekare)
Unära operatorn “Ampersang” &
‚ I uttryck framför variabel: Hämta variabelns adress
‚ I deklarationer: Skapa referensvariabel (alias tillvariabel)
Notera 1: Båda operatorerna finns även i binära varianterNotera 2: “variabel” ovan inkluderar “pekarvariabel”
27 / 52
Stjärna och Ampersang cont.
int var{4};int* ptri{ &var }; // Pekardeklaration och adressoperatorncout << *ptri; // Avreferering
// Tre referensdeklarationerostream& operator<<(ostream& lhs, Complex const& rhs){//...
}
28 / 52
Vad händer här?
Ändras adressen eller vad som ligger på den adressen?
int var{42};int* ptri{&var};ptri = 109;cout << var << endl;
29 / 52
Vad händer här?
Ändras adressen eller vad som ligger på den adressen?
int var{42};int* ptri{&var};*ptri = 109;cout << var << endl;
1 Vad gjorde vi förra gången?FelhanteringOperatorerTypkonvertering
2 Grundläggande om pekare3 New4 Destruktorer5 Composition
31 / 52
Vad gör new?
‚ Vilka delar av minnetallokeras till c++ vidstart?
‚ New ger oss minne iheapen / free store
‚ Massor av ansvar...
32 / 52
Varför behövs både stack och heap(new)?
Varför pekare ‐ räcker det inte med vanliga variabler?Varför new ‐ räcker det inte med vanliga variabler?I alla tidigare slides behövs varken pekare eller new!Men vad händer här?
int* give_me_more_memory() {int memory{}int* ptri{&memory}return ptri // serious problem!
}int main() {
int* ptri{ give_me_more_memory() }*ptri = 4711
}
33 / 52
Minnesallokering på heapen och nåbar läcka
Minnesläcka: Vad händer här?
int* give_me_more_memory(){
int* ptri{ new int{} };return ptri; // who is responsible?
}
int main(){
int* ptri{ give_me_more_memory() }*ptri = 4711cout << *ptri
} // leak: serious problem
34 / 52
Onåbar minnesläcka och återlämning med delete
Minnesläcka: Vad händer här?
int main(){
int* ptri{ give_me_more_memory() }*ptri = 4711cout << *ptriptri = give_me_more_memory() // leak: serious problemdelete ptri
}
35 / 52
Ansvarsfördelning och minnestätning
void free_up_this_memory(int* adr) {delete adr;
}int main() {
int* ptri{ give_me_more_memory() };*ptri = 4711;cout << *ptri;free_up_this_memory(ptri);ptri{ give_me_more_memory() };*ptri = 17;cout << *ptri;free_up_this_memory(ptri);
}
36 / 52
Fortfarande finns en enklare lösning
int main(){
int* ptri{ new int{4711} };cout << *ptri;delete ptri;int* ptri{ new int{17} };cout << *ptri;delete ptri;
}
37 / 52
Se upp för ogiltiga pekare!
int main(){
int* ptri{ new int{4711} }cout << *ptridelete ptri*ptri = 17 // serious problem!cout << *ptri // serious problem!
}
38 / 52
Se upp för stackadresser!
int main(){
int var{17};int* ptri{ new int{4711} }cout << ptridelete ptriptri = &varcout << ptridelete ptri // serious problem!
}
39 / 52
Enklast är ändå bäst och säkrast
int main(){
int ptr{4711};cout << ptri;
int ptr{17};cout << ptri;
}
Så hur blir pekare meningsfulla?
40 / 52
Dynamisk datastruktur!
Med verktygen pekare och new kan vi skapa datatyper somgår att bygga ut!
struct data_and_pointer{
int stored_data;data_and_pointer* more_memory;
};
41 / 52
void* och cast
‚ Undvik void*‚ Vid hantering av pekare och
new är vi på en låg nivå‚ Typsystemet är vårt sista skydd‚ Poängen är att ni ska låta bli i
nästan alla fall
void* pv = new int{0}*pv = 2 // Error, varför?int pi{pv} // Error, varför?pv[1] // Not subscriptableint* pi = static_cast<int*>(pv)
1 Vad gjorde vi förra gången?FelhanteringOperatorerTypkonvertering
2 Grundläggande om pekare3 New4 Destruktorer5 Composition
43 / 52
Block och destruktorer‚ När en variabel går ut ur scope
kommer den destrueras‚ När ett objekt destrueras körs
dess destruktor‚ Ett objekt destrueras när dess
minne avallokeras‚ Rekursivt
{vector<int> v{};v.push_back(4);cout << v.at(0) << endl;
} //Här destrueras v
class Array{public:Array();//Konstruktor~Array();//Destruktor
private://array containing dataint* data;
}
44 / 52
Block och destruktorer
class Array{public:Array(int size);//Konstruktor~Array();//Destruktor
private://array containing dataint* data;
}
Array::Array(int size): data{new int[size]}{}
Array::~Array(){delete[] data;
}
45 / 52
Destruktor vs Konstruktor
Det är Konstruktorns jobb attinitiera datamedlemmarna korrekt.
Det är destruktorns jobb attdestruera datamedlemmarnakorrekt.
46 / 52
Pekare och medlemmar
class Array{public:Array(int size);~Array();void add(int index,
int value);int get(int idx) const;
private:int* data;
};
int main(){Array* pa = new Array{4};pa.add(0, 4); // Syntaxfel(*pa).add(0, 4); // Vad? Hur?pa -> add(0, 4); // Skillnad?
}
47 / 52
Destruktor vs Konstruktor konceptuellt
Destructors are cenceptually simple but are the foundationfor many of the most effective C++ programmingtechniques. The basic idea is simple:
‚ Whatever resources a class object needs to function, itacquires in a constructor.
‚ During the object’t lifetime it may release resourcesand acquire new ones.
‚ At the end of the object’ts lifetime, the destructorreleases all resources still owned by the object.
Från: Bjarne S. 2014 Programming Principles...
1 Vad gjorde vi förra gången?FelhanteringOperatorerTypkonvertering
2 Grundläggande om pekare3 New4 Destruktorer5 Composition
49 / 52
Vad är composition
‚ Nyckelkoncept inom OOD och OOP
‚ Medlemmen är en del av objektet
‚ Medlemmen kan bara tillhöra ett objekt åt gången
‚ Medlemmens Lifetime styrs av objektet
‚ Medlemmen känner inte till objektet
51 / 52
Vi tänker oss en stack
‚ Vad är en stack?‚ Hur kan vi implementera
en stack?‚ Med pekare?‚ Syntaktiskt‐/Semanstiskt
korrekt
Head
Node
Node
5
10
52 / 52
Nästlad klass‚ Tydligt relation mellan
Element och Stack‚ Inkapslad trots public
åtkomst‚ Vilken klass hör vad
till?
class Stack {public:Stack();Stack(std::initializer_list<int> il);~Stack();void push(int v);int pop();std::string to_string();bool empty();
private:struct Element {Element* next;int value;
};Element* first;
};ostream& operator<<(ostream& os,
Stack const& lhs);