tdiu20- objektorienterad programmeringic++- …tdiu20/info/slides/fo3.pdf8/57 konstruktor varför?...
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