tdiu20- objektorienterad programmeringic++- …tdiu20/info/slides/fo3.pdf8/57 konstruktor varför?...

Post on 18-Aug-2020

2 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

TDIU20 -Objektorienteradprogrammering i c++ -föreläsning 3Pontus Haglund

Department of Computer and information science

1 Vad har vi gjort hittills2 Felhantering3 Operatorer4 binära operatorer5 unära operatorer6 user-defined literal7 Typomvandling

2 / 57

Dagens föreläsning

1. Vad har vi gått igenom hittills?

2. Kort upprepning av koncept

3. Felhantering: throw, try, catch

4. Typkonvertering

5. Operatorer för complex

1 Vad har vi gjort hittills2 Felhantering3 Operatorer4 binära operatorer5 unära operatorer6 user-defined literal7 Typomvandling

4 / 57

Vad har vi gått igenom hittills?

• Klass vs Objekt

• Struktur av en klass

• Inkapsling

• Datamedlemmar

• Konstruktorer

• TDD

5 / 57

Klass vs Objekt

• Skillnaden mellanritning och hus

• Klassen beskriver hurobjektet ska se ut

• Ett objekt är en instansav klassen (minnet)

6 / 57

Aggregate class

//main.cppint main(){

Card h2{2, "hearts"};cout << h2.suit << endl;

}

//card.hclass Card{public:string suit;int value;

};

hearts

7 / 57

Private

Varför?

//main.cppint main(){

Card h2{2, "hearts"};cout << h2.suit << endl;

}

//card.hclass Card{private:string suit;int value;

};

Vad går sönder?

8 / 57

Konstruktor

Varför?

//main.cppint main(){

Card h2{2, "hearts"};cout << h2.suit << endl;

}

//card.hclass Card{public:Card(int v, string s): suit{s}, value{v} {}private:string suit;int value;

};

Vad är fortfarande trasigt?

9 / 57

Getters

Varför?

//main.cppint main(){

Card h2{2, "hearts"};cout << h2.get_suit() << endl;

}

//card.hclass Card{public:Card(int v, string s): suit{s}, value{v} {}get_suit() const { return suit; }get_value() const { return value; }private:string suit;int value;

};

Har vi nu fått tillbaka all funktionalitet?

10 / 57

Setters

Nästan...

//main.cppint main(){

Card h2{2, "hearts"};cout << h2.get_suit() << endl;

}

//card.hclass Card{public:Card(int v, string s): suit{s}, value{v} {}get_suit() const { return suit; }set_suit(string s) { suit = s; }get_value() const { return value; }set_value(int v) { value = v; }private:string suit;int value;

};

Har vi nu fått tillbaka all funktionalitet?

11 / 57

Inkapsling

• Det handlar inte att vi inte får ändra pådatamedlemmar som är private.

• Det kan vi använda const för.

• Ofta är det lämpligt att kunna ändra på datan.

• Varför håller vi på med detta då?

1 Vad har vi gjort hittills2 Felhantering3 Operatorer4 binära operatorer5 unära operatorer6 user-defined literal7 Typomvandling

13 / 57

Felhantering i c++

• Testar att göra övre blocket• Vid fel (en throw) hoppa tillett av catch-blocken

• Fel kastas upp en nivå iprogrammet

try //Försök göra{

}//Fånga exceptioncatch(logic_error& e){

}catch(...){

}

14 / 57

Anropa underprogram

Vanlig ordning...

int main(){try{

fun1();//...

}catch{exception& e}{

cerr << e.what();}

}

void fun1(){//...fun2();//...return;

}

void fun2{return;

}

15 / 57

Anropa underprogram

Vad händer om vi kastar ett fel?

#include <stderr>

int main(){try{

fun1();//...

}catch{exception& e}{

cerr << e.what();}

}

void fun1(){//...fun2();//...return;

}

void fun2{throw logic_error{"Error message"};

}

16 / 57

Felhantering och klasser

• Objekt skall alltid varai valid states

• Objekt finns i c++efter konstruktornkörts utan fel

17 / 57

Ok...

• Jaha....• Det var väll gulligt,men vad har det attgöra med klasser?

18 / 57

Avbryt konstruktor

Enda sättet att avbryta en konstruktorclass Cls {

Cls(int a){a}{//...if (is_invalid()){throw logic_error("message");

}//...

}//...

};

19 / 57

Att tänka på

• try är i princip lika snabbt som vilken annan kodsom helst

• Exceptions är VÄLDIGT långsamma när du kastardem

• Använd endast i exceptionella situationer

• Använd INTE exceptions som en styrstruktur

• Mycket långsammare

• Dåligt praxis

20 / 57

noexcept

• noexcept är ett löfte tillkompilatorn

• Vid fel dör programmet• Tänk efter noggrant• Får inte läcka fel men kan fånga

class Card{//...

int get_value() const noexcept{return value;

}//...}

21 / 57

Strömmar

• Dokumenterat istd::basic_ios

• goodbit - allt funkar• badbit - spik i disken• failbit - i/o hanteringmisslyckades

• eofbit - har nått slutetav filen

int main(){

std::ostringstream stream;

if (!stream.fail()) {std::cout << "stream is not fail\n";

}

stream.setstate(std::ios_base::failbit);

if (stream.fail()) {std::cout << "now stream is fail\n";

}

if (!stream.good()) {std::cout << "and stream is not good\n";

}}

1 Vad har vi gjort hittills2 Felhantering3 Operatorer4 binära operatorer5 unära operatorer6 user-defined literal7 Typomvandling

23 / 57

Operator?

• Finns inommatematiken

• Finns inomprogrammering

• Verkar på operander

24 / 57

Skriv din egen operator

• Klasser kan ha sinaegna operatorer

• -• +• string• mfl

int main(){

Complex c1{1,2};Complex c2{2,1};cout << c1 + c2 << endl;

}

Varför fungerar/fungerarinte ovantstående?

25 / 57

När använder vi operatorer i c++?

Complex c1{1, 3};Complex c2{2, 1};Complex c3 = c1 + c2;

26 / 57

Hur ser c++ på det?

Complex c1{1, 3};Complex c2{2, 1};c1 + c2;c2 + c1;

Complex c1{1, 3};Complex c2{2, 1};c1.operator+(c2);c2.operator+(c2);

27 / 57

Ett annat exempel

Complex c1{1, 3};cout << c1;

Complex c1{1, 3};cout.operator<<(c1);

Ok det var enkelt... eller?

28 / 57

Det finns lite olika varianter

• binära

• medlemmar

• icke medlemmar

• unära

• user-defined literals(användardefinerade literaler?)

1 Vad har vi gjort hittills2 Felhantering3 Operatorer4 binära operatorer5 unära operatorer6 user-defined literal7 Typomvandling

30 / 57

Binära operatorer

Har 2 operander.

//Exempelc1 + c2;c3 = c1;cout << c3;//Hur c++ ser detc1.operator+(c2);c3.operator=(c1);cout.operator<<(c3);

//Objektet är vänstersidan//I Complex.hclass Complex{

public://...Complex operator+(Complex const& rhs);Complex& operator=(Complex const& rhs);Ostream& operator<<(Complex const& rhs);//...

};

Men om objektet är vänstra operanden...Hur funkar det med operator<< ?

31 / 57

Inne eller utanför klassen?

Vi kan inte ändra i ostream/cout

//Exempelc1 + c2;c3 = c1;cout << c3;//Hur c++ ser detc1.operator+(c2);c3.operator=(c1);operator<<(cout, c3);

//Objektet är vänstersidan//I Complex.hclass Complex{public://...Complex operator+(Complex const& rhs) const;Complex& operator=(Complex const& rhs);//friend Ostream& operator<<... ?// Friend?//...

};Ostream& operator<<(Ostream & os, Complex const& rhs);

32 / 57

Implementation av binär operator +//h-filclass Complex{

public://...Complex operator+(Complex const& rhs) const; //c1 + c2//...

};

//cc-filComplex Complex::operator+(Complex const& rhs) const{

int new_real{real + rhs.real};int new_imag{imag + rhs.imag};Complex new_complex_number{new_real, new_imag};return new_complex_number;

}

Complex Complex::operator+(Complex const& rhs){

return Complex{real + rhs.real, imag + rhs.imag};}

33 / 57

Implementation av binär operator =

//h-filclass Complex{

public://...Complex& operator=(Complex const& rhs); //c1 = c2//...

};

//cc-filComplex& Complex::operator=(Complex const& rhs){

real = rhs.real;imag = rhs.imag;return *this; //dereference operator

}

34 / 57

Implementation av binär operator <<

//h-filclass Complex{

//...};

ostream& operator<<(ostream & lhs, Complex const& rhs); // cout << c1;

//cc-filostream& operator<<(ostream & lhs, Complex const& rhs){

lhs << rhs.get_real() << " + " << rhs.get_imag() << "i";return lhs;

}

35 / 57

Vadå ostream? Varför inte cout?

• ostream• en klass• cout• ostringstream• ofilestream• ...

• cout• objekt av typen ostream• globalt• skriver till stdout

• cerr• som cout• fast till stderr

36 / 57

Så varför inte cout?

TEST_CASE("Cout test"){Complex c1{1, 2};cout << c1;// ????// Dear user please check// that output is correct// in your shell...

}

1 + 2i

37 / 57

Så varför inte cout?

TEST_CASE("Cout test"){Complex c1{1, 2};cout << c1;// ????// Dear user please check// that output is 1 + 2i// in your shell...

}

1 + 2i

38 / 57

ostream!

TEST_CASE("String stream test"){Complex c1{1, 2};stringstream sstream{};sstream << c1;CHECK( sstream.str() == "1 + 2i" );

}

1 Vad har vi gjort hittills2 Felhantering3 Operatorer4 binära operatorer5 unära operatorer6 user-defined literal7 Typomvandling

40 / 57

Unära operatorer

Har 1 operand.

//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...

41 / 57

Implementera preinkrement

//h-filenclass Complex{

public://...Complex& operator++(); // ++c1 <------Complex operator++(int); // c1++Complex& operator--(); // --c1Complex operator--(int); // c1--Complex& operator-(); // -c1//...

};

Complex& Complex::operator++(){

real += 1;imag += 1;return *this;

}

42 / 57

Implementera postinkrement//h-filenclass Complex{

public://...Complex& operator++(); // ++c1Complex operator++(int); // c1++ <------Complex& operator--(); // --c1Complex operator--(int); // c1--Complex& operator-(); // -c1//...

};

Complex Complex::operator++(int){

Complex tmp{*this};real += 1;imag += 1;return tmp;

}

43 / 57

Implementera unärt minus

//h-filenclass Complex{

public://...Complex& operator++(); // ++c1Complex operator++(int); // c1++Complex operator--(); // --c1Complex operator--(int); // c1--Complex operator-(); // -c1 <------//...

};

Complex& Complex::operator-(){

real *= -1;imag *= -1;return *this;

}

1 Vad har vi gjort hittills2 Felhantering3 Operatorer4 binära operatorer5 unära operatorer6 user-defined literal7 Typomvandling

45 / 57

user-defined literals

Allows integer, floating-point, character, and stringliterals to produce objects of user-defined type bydefining a user-defined suffix.-https://en.cppreference.com/w/cpp/language/user_literal-Ett ganska avancerat koncept men kan vara användbartibland.

46 / 57

Usecase

Säg att vi vill skriva ett program där följande syntaxfungerar för att skapa komplexatal.int main(){

Complex c1 = 1 + 2_icout << c1 << endl;cout << 1 + 3_i << endl;

}

47 / 57

2_i

För att delen med 2_i ska fungera beghöver vi ha enuser-defined literal. Det är en operator på formatet:Complex operator "" _i(unsigned long long int i);

Den returnerar ett objekt av typen Complex för attdetta ska fungera:Complex operator "" _i(unsigned long long int i){

return Complex{0, static_cast<int>(i)};}

48 / 57

Hur sätter vi ihop dem?

//I klassenComplex Complex::operator "" _i(unsigned long long int i){

return Complex{0, static_cast<int>(i)};}

//Utanför klassenComplex operator+(int lhs, Complex const& rhs){

return Complex{lhs, rhs.i};}

Complex c{1+2_i};Complex c2 = 1+2_i //....cout << 1+2_i;

1 Vad har vi gjort hittills2 Felhantering3 Operatorer4 binära operatorer5 unära operatorer6 user-defined literal7 Typomvandling

50 / 57

Typomvandling

• Att omvandla en typ till en annan• Exempelvis göra om en int till endouble

• Varför!• Hur?

51 / 57

static cast

• Kontrolleras compile time

• Krävs att objektet vet hur det konverteras till typenstring 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?

52 / 57

dynamic cast

• Kontrolleras run time

• Krävs att objektet vet hur det konverteras till typen

• Är bara användbart när man castar ensuperklass-pekare till en subklass-pekare

string cs1 = dynamic_cast<string>( Complex{1, 3} );//Funkar inteComplex c{1, 3};string cs2 = dynamic_cast<string>( c );//Funkar inte

• Hur kan vi se till att Complex vet hur den skallkonverteras till string?

53 / 57

Hur vet klassen?

Genom att lägga till den operatorn i klassen

//Unary operator//MedlemsfunktionComplex::operator string(){return to_string();

}

class Complex{

//...operator string();//...

}

Observera:

• Ingen returtyp

• Fungerar för andra typer

54 / 57

Typkonverterande konstruktorer

• operatorn sköterkonvertering från din typ tillen annan

• konstruktorn sköterkonvertering från en annantyp till din typ

//h-filclass Complex{//...Complex(std::string const& str);//...

}

55 / 57

C-style

tldr: Använd intestring complex_string = (string) Complex{1, 2};// VSstring complex_string = static_cast<string>(Complex{1, 2});// ...

56 / 57

Strömmar och konvertering

Strömmar är ett utmärkt sätt att konvertera till rättfrån början:int a;char b;int c;char d;double e;// 1 : 2 : 4.0cin >> a >> b >> c >> d >> e;

57 / 57

fler sätt

• stoi

• to_string

• string()

www.liu.se

top related