Orientação a objetos
Transcrição
Orientação a objetos
Programação orientada a objetos com C / C++ em ambiente multiplataforma n Parte 4 – Orientação a objetos (adendo) – versão 6.1 de 10 de Julho de 2002 n Por Sergio Barbosa Villas-Boas – www.del.ufrj.br/~villas – [email protected] copyright © sbVB sbVB http://www.del.ufrj.br/~villas cout e sobrecarga do insersor (<<) #include <iostream.h> void main() { // cout << "Hello "; cout.operator<<("hello"); Hello Hello i=4 // cout << "Hello" << endl; (cout.operator<<("hello")).operator<<(endl); int i = 4; // cout << "i=" << i << endl; ((cout.operator<<("i=")).operator<<(i)).operator<<(endl); } copyright © sbVB http://www.del.ufrj.br/~villas 1 Sobrecarga do insersor (<<) e extrator (>>) #include <iostream.h> class myClass { public: int m_i; myClass(int i = 0) {m_i = i;} // construtor friend ostream & operator <<(ostream & s, const myClass & z) { s << z.m_i; // s.operator<<(z.m_i); return s; } friend istream & operator>>(istream & s, myClass & z) { s >> z.m_i; // s.operator>>(z.m_i); return s; } }; Entre com void main() a=22 { myClass a; cout << "Entre com o dado:"; // cin >> a; não é operator>>(cin, a); o dado:22 "cin.operator>>(a);" // cout << "a=" << a << endl; http://www.del.ufrj.br/~villas copyright © sbVB (operator<<(cout.operator<<("a="), a)).operator<<(endl); } Escrevendo arquivo texto (1) #include <fstream.h> class myClass { public: int m_i[2]; friend ostream & operator << (ostream & s, const myClass & a) { s << a.m_i[0] << endl << a.m_i[1]; // não incluir << endl return s; c:\xxx\fileout.dat } 3.14↵ ↵ }; void main() { 2.3456↵ ↵ float pi=3.14; 12↵ ↵ double d = 2.3456; 24↵ ↵ myClass z; z.m_i[0] = 12; z.m_i[1] = 24; ofstream myFile; const char* fname = "c:\\xxx\\fileout.dat"; myFile.open (fname); if (!myFile) cout << "File " << fname << " not open"; myFile << fname << endl; myFile << pi << endl; myFile << d << endl; myFile << z << endl; // myFile.close(); // not necessary, http://www.del.ufrj.br/~villas //because by destructor copyright © sbVBfile is closed } 2 #include <fstream.h> class myClass { public: int m_i[2]; friend ostream & operator << (ostream & s, const myClass & a) { s << a.m_i[0] << endl << a.m_i[1]; // não incluir << endl return s; } }; void putToFileOrConsole(ostream & device, float pi, double d, myClass z, const char *fname) { c:\xxx\fileout.dat device << fname << endl; 3.14↵ ↵ device << pi << endl; 2.3456↵ ↵ device << d << endl; 12↵ ↵ device << z << endl; 24↵ ↵ } void main() { float pi=3.14; double d = 2.3456; myClass z; z.m_i[0] = 12; z.m_i[1] = 24; c:\>program↵ ↵ ofstream myFile; c:\xxx\fileout.dat const char* fname = "c:/xxx/fileout.dat"; 3.14 fname = "c:\\xxx\\fileout.dat"; 2.3456 myFile.open (fname); 12 if (!myFile) 24 cout << "File " << fname << " not open"; putToFileOrConsole(myFile, pi, d, z, fname); c:\> putToFileOrConsole(cout, pi, d, z, fname); http://www.del.ufrj.br/~villas copyright © sbVB } Escrevendo arquivo texto (2) #include <iostream.h> #include <fstream.h> #include "vblib.h" class myClass { public: int m_i[2]; friend ostream & operator << (ostream & s, const myClass & a) { s << a.m_i[0] << endl << a.m_i[1]; // não incluir << endl return s; } friend istream & operator >> (istream & s, myClass & a) { s >> a.m_i[0] >> a.m_i[1]; return s; } c:\>program↵ ↵ }; file=c:\xxx\fileout.dat void main() { pi=3.14 VBString str; d=2.3456 float pi; z=12 double d; myClass z; 24 ifstream myFile; c:\> const char* fname = "c:\\xxx\\fileout.dat"; myFile.open (fname); if (!myFile) { cout << "File " << fname << " not open" << endl; } else { myFile >> str >> pi >> d >> z; cout << "file=" << str << endl << "pi=" << pi << endl << "d=" << d << endl << "z=" << z << endl; http://www.del.ufrj.br/~villas copyright © sbVB } } Lendo arquivo texto 3 #include <fstream.h> #include "vblib.h" // VBString class person { // private attributes VBString m_name; VBString m_address; VBString m_telephone; float m_weight; vários atributos na classe Lendo/escrevendo classe com múltiplos atributos public: // public access methods void setName(VBString name) { m_name = name; }; void setAddress(VBString address) { m_address = address; }; void setTelephone(VBString telephone) { m_telephone = telephone;}; void setWeight(float weight) { m_weight = weight;}; VBString getName() { return m_name; }; VBString getAddress() { return m_address;}; VBString getTelephone() { return m_telephone; }; float getWeight() { return m_weight;}; friend ostream & operator << (ostream & s, const person & obj) { s << obj.m_name << endl << obj.m_address << endl << obj.m_telephone << endl << obj.m_weight; // não incluir << endl return s; } friend istream & operator >> (istream & s, person & obj) { s >> obj.m_name >> obj.m_address >> obj.m_telephone >> obj.m_weight; VBString dummy; s >> dummy; // read the <return> to synchronize file pointer return s; http://www.del.ufrj.br/~villas copyright © sbVB } }; Lendo/escrevendo classe com múltiplos atributos (2) void write() { int times = 5; person p; VBString timesStr; p.setName("test name"); p.setAddress("test address"); p.setTelephone("test telephone"); ofstream myFile; const char* fname = "c:\\xxx\\fileout.txt"; myFile.open (fname); if (!myFile) { cout << "File " << fname << " not open" << endl; } else { for (int i=0 ; i < times ; i++) { timesStr = ""; timesStr += i; // convert int to string p.setName("test name " + timesStr); p.setWeight(1.1+i); myFile << p << endl; // write person object to file } } } copyright © sbVB http://www.del.ufrj.br/~villas 4 Lendo/escrevendo classe com múltiplos atributos (3) void read() { person p; ifstream myFile; const char* fname = "c:\\xxx\\fileout.txt"; myFile.open (fname); if (!myFile) { cout << "File " << fname << " not open" << endl; } else { while (true) { // loop to read entire file myFile >> p; // read person object from file if (myFile.eof()) break; cout << p << endl; // write person object to console } } } copyright © sbVB c:\>program↵ ↵ test name 0 test address test telephone 1.1 test name 1 test address test telephone 2.1 test name 2 test address test telephone 3.1 test name 3 test address test telephone 4.1 test name 4 test address test telephone 5.1 c:\> http://www.del.ufrj.br/~villas Lendo/escrevendo classe com múltiplos atributos (versão 2) #include <fstream.h> #include "vblib.h" // VBString class Person { // private attributes vários VBString m_name; atributos VBString m_address; VBString m_telephone; na classe float m_weight; atributos char m_token, m_token_substitute; public: auxiliares Person() { m_token = '|'; m_token_substitute='_'; } // public access methods void setName(VBString name) { m_name = name; }; void setAddress(VBString address) { m_address = address; }; void setTelephone(VBString telephone) { m_telephone = telephone;}; void setWeight(float weight) { m_weight = weight;}; VBString getName() { return m_name; }; VBString getAddress() { return m_address;}; VBString getTelephone() { return m_telephone; }; float getWeight() { return m_weight;}; // (continua) copyright © sbVB http://www.del.ufrj.br/~villas 5 Lendo/escrevendo classe com múltiplos atributos (versão 2) (2) // continuação do slide anterior friend ostream & operator << (ostream & s, const Person & obj) { char strToken[2], strTokenSubs[2]; strToken[0] = obj.m_token; strToken[1] = 0; // terminate string strTokenSubs[0] = obj.m_token_substitute; strTokenSubs[1] = 0; // terminate string VBString aux; aux = obj.m_name; aux.strschg(strToken,strTokenSubs); s << aux << obj.m_token; aux = obj.m_address; aux.strschg(strToken,strTokenSubs); s << aux << obj.m_token; aux = obj.m_telephone; aux.strschg(strToken,strTokenSubs); s << aux << obj.m_token; s << obj.m_weight; // não incluir << endl return s; } friend istream & operator >> (istream & s, Person & obj) { VBString aux; s >> aux; // read all attributes of object in one string obj.m_name = aux.strtok(obj.m_token,0); obj.m_address = aux.strtok(obj.m_token,1); obj.m_telephone = aux.strtok(obj.m_token,2); obj.m_weight = atof(aux.strtok(obj.m_token,3)); return s; http://www.del.ufrj.br/~villas copyright © sbVB } }; Lendo/escrevendo classe com múltiplos atributos (versão 2) (3) n Aspecto do arquivo de saída (e também no console) usando a nova versão (c:\xxx\fileout.txt) test name 0|test address|test test name 1|test address|test test name 2|test address|test test name 3|test address|test test name 4|test address|test copyright © sbVB telephone|1.1↵ ↵ telephone|2.1↵ ↵ telephone|3.1↵ ↵ telephone|4.1↵ ↵ telephone|5.1↵ ↵ http://www.del.ufrj.br/~villas 6 Copiando arquivo texto para console #include <fstream.h> #include "vblib.h" void main() { VBString line; const char* fname = "c:\\xxx\\fileout.txt"; ifstream myFile; myFile.open(fname); if (!myFile) { cout << "File " << fname << " not open" << endl; } while (true) // loop to read entire file { myFile >> line; // one line if (myFile.eof()) break; cout << line << endl; // out to console } } copyright © sbVB c:\>program↵ ↵ test name 0 test address test telephone 1.1 test name 1 test address test telephone 2.1 test name 2 test address test telephone 3.1 test name 3 test address test telephone 4.1 test name 4 test address test telephone 5.1 c:\> http://www.del.ufrj.br/~villas Copiando arquivo texto para console (variante do programa usando string change feature) #include <fstream.h> #include "vblib.h" void main() { VBString line; const char* fname = "c:\\xxx\\fileout.txt"; ifstream myFile; myFile.open(fname); if (!myFile) { cout << "File " << fname << " not open" << endl; } while (true) // loop to read entire file { myFile >> line; // one line if (myFile.eof()) break; line.strschg("test","TEST"); line.strschg("name","Villas"); cout << line << endl; // out to console } http://www.del.ufrj.br/~villas copyright © sbVB } c:\>program↵ ↵ TEST Villas 0 TEST address TEST telephone 1.1 TEST Villas 1 TEST address TEST telephone 2.1 TEST Villas 2 TEST address TEST telephone 3.1 TEST Villas 3 TEST address TEST telephone 4.1 TEST Villas 4 TEST address TEST telephone 5.1 c:\> 7 Arquivo binário (Visual C++) exemplo: copiando um arquivo binário // Visual C++ #include <fstream.h> #define TYPE unsigned char void main() { TYPE buffer; // to write, binary mode ofstream writeFile; ifstream readFile; const char* fname = "c:\\xxx\\test.jpg"; const char* fname2 = "c:\\xxx\\test2.jpg"; readFile.open(fname, ios::binary); if (!readFile) cout << "File " << fname << " not open"; writeFile.open(fname2, ios::binary); if (!writeFile) cout << "File " << fname2 << " not open"; while (true) { readFile.read((unsigned char*)&buffer, sizeof(TYPE)); if (readFile.eof()) break; writeFile.write((unsigned char*)&buffer, sizeof(TYPE)); http://www.del.ufrj.br/~villas } copyright © sbVB } Arquivo binário (g++) exemplo: copiando um arquivo binário // unix, g++ #include <fstream.h> #define TYPE unsigned char void main() { TYPE buffer; // to write, binary mode ofstream writeFile; ifstream readFile; const char* fname = "c:\\xxx\\test.jpg"; const char* fname2 = "c:\\xxx\\test2.jpg"; readFile.open(fname); if (!readFile) cout << "File " << fname << " not open"; writeFile.open(fname2); if (!writeFile) cout << "File " << fname2 << " not open"; while (true) { readFile.read((unsigned char*)&buffer, sizeof(TYPE)); if (readFile.eof()) break; writeFile.write((unsigned char*)&buffer, sizeof(TYPE)); http://www.del.ufrj.br/~villas } copyright © sbVB } 8 Tratamento de exceção exception handling n Palavras reservadas para tratamento de exceção – try (tentar) – catch (capturar) – throw (jogar) n n Em java o tratamento de exceção é muito parecido com C++. Tratamento de exceção é de certa forma parecido com “goto”, mas respeita a necessidade de se destruir os objetos. copyright © sbVB http://www.del.ufrj.br/~villas Bloco try-catch linha de execução do programa try catch catch catch bloco try-catch linha de execução do programa copyright © sbVB http://www.del.ufrj.br/~villas 9 Exemplo de tratamento de exceção #include <iostream.h> class SomeClass { public: SomeClass() { cout << "SomeClass constructor" << endl; }; ~SomeClass() { cout << "SomeClass destructor" << endl; }; }; float divide(float a, float b) // function under test { SomeClass testObject; float ret; if (b == 0) throw "Can't divide by zero"; In main. else SomeClass constructor ret = a / b; SomeClass destructor SomeClass testObject2; EXCEPTION: Can't divide by zero return ret; Back in main. } void main() { cout << "In main." << endl; try { float z = divide(1.1,0); } catch (const char *message) { cout << "EXCEPTION: " << message << endl; } cout << "Back in ©main." << endl; http://www.del.ufrj.br/~villas sbVB copyright } bloco try-catch Mais de um catch handler try catch (catchHandler1) catch (catchHandler2) catch (catchHandler3) copyright © sbVB bloco try-catch http://www.del.ufrj.br/~villas 10 #include <iostream.h> class CatchHandler1 { public: const char *ShowExplanation() const { return "CatchHandler 1 Explanation"; } }; class CatchHandler2 { public: const char *ShowExplanation() const { return "CatchHandler 2 Explanation"; } }; void FunctionUnderTest(int i) { In main. CatchHandler1 C1; EXCEPTION CatchHandler CatchHandler2 C2; if (i == 1) throw C1; Back in main. if (i == 2) throw C2; } void main() { cout << "In main." << endl; try { FunctionUnderTest(1); } catch (CatchHandler1 E) { cout << "EXCEPTION " << E.ShowExplanation() << endl; } catch (CatchHandler2 E) { cout << "EXCEPTION " << E.ShowExplanation() << endl; } cout << "Back in main." << endl; } Exemplo de mais de um catch handler 1 Explanation bloco try-catch Capturador genérico generic catch try { catch catch catch catch copyright © throw obj4; } (catchHandler1) (catchHandler2) (catchHandler3) (...) // catch anything sbVB http://www.del.ufrj.br/~villas 11 #include <iostream.h> class CatchHandler1 { public: const char *ShowExplanation() const { return "CatchHandler 1 Explanation"; } }; class CatchHandler2 { public: const char *ShowExplanation() const { return "CatchHandler 2 Explanation"; } }; void main() In main. { cout << "In main." << endl; UNKNOWN EXCEPTION try Back in main. { throw 3.3; // throw double } catch (CatchHandler1 E) { cout << "EXCEPTION " << E.ShowExplanation() << endl; } catch (CatchHandler2 E) { cout << "EXCEPTION " << E.ShowExplanation() << endl; } catch (...) // generic catch { cout << "UNKNOWN EXCEPTION" << endl; } cout << "Back in main." << endl; } Exemplo de capturador genérico Exemplo de tratamento de exceção no acesso a disco flexível #include <fstream.h> void openFile(ofstream & myFile) { const char *fileName = "a:\\t.txt"; ifstream auxFile; auxFile.open(fileName, ios::nocreate); // check if file exists if (auxFile) throw "file exists"; // if file exists myFile.open(fileName); // try to open file to write if (!myFile) throw "can't open file (is there a disk in drive?)"; } copyright © sbVB http://www.del.ufrj.br/~villas 12 Exemplo (continuação) void main() { ofstream myFile; bool fileIsOpen = true; try { openFile(myFile); } catch (const char *message) { cout << "EXCEPTION:" << message << endl; fileIsOpen = false; } if (fileIsOpen) { cout << "Writing to file" << endl; myFile << "test" << endl; } } Casos: 1) OK (no exception) 2) EXCEPTION: file exists http://www.del.ufrj.br/~villas copyright © sbVB can't open 3) EXCEPTION: file (is there a disk in drive?) Namespace Recurso de linguagem C++ para isolamento de nomes. n Não é estruturalmente um recurso de “programação orientada a objetos”. n copyright © sbVB http://www.del.ufrj.br/~villas 13 Namespace (2) This is the error handler of oneNamespace #include <iostream.h> This is the error handler of otherNamespace namespace oneNamespace { void errorHandler() { cout << "This is the error handler of oneNamespace" << endl; } } namespace otherNamespace { void errorHandler() { cout << "This is the error handler of otherNamespace" << endl; } } void main() { oneNamespace::errorHandler(); otherNamespace::errorHandler(); http://www.del.ufrj.br/~villas copyright © sbVB } Namespace (3) This is the error handler of oneNamespace #include <iostream.h> This is the error handler of otherNamespace namespace oneNamespace { void errorHandler() { cout << "This is the error handler of oneNamespace" << endl; } } namespace otherNamespace { void errorHandler() { cout << "This is the error handler of otherNamespace" << endl; } } using namespace oneNamespace; void main() { errorHandler(); // uses namespace oneNamespace by default otherNamespace::errorHandler(); http://www.del.ufrj.br/~villas copyright © sbVB } 14 Namespace (4) #include <iostream.h> namespace oneNamespace { void errorHandler() { cout << "This is the error handler of oneNamespace" << endl; } } namespace otherNamespace { void errorHandler() { cout << "This is the error handler of otherNamespace" << endl; } } using namespace oneNamespace; using namespace otherNamespace; void main() { errorHandler(); // error ! ambiguous http://www.del.ufrj.br/~villas copyright © sbVB } Namespace aberto (continuação do namespace) #include <iostream.h> namespace oneNamespace { void errorHandler() { cout << "This is the error handler of oneNamespace" << endl; } } namespace otherNamespace { void errorHandler() { cout << "This is the error handler of otherNamespace" << endl; } } namespace oneNamespace // continuation of oneNamespace { void otherFun() { cout << "otherFun of oneNamespace" << endl; http://www.del.ufrj.br/~villas copyright © sbVB } } 15 Biblioteca padrão de C++ usando namespace std Use headers sem extensão .h n Todos os headers padrão foram reescritos com namespace. n Não misture header padrão comum (*.h) com header padrão usando namespace (sem .h). n copyright © sbVB http://www.del.ufrj.br/~villas Biblioteca padrão de C++ usando namespace (2) #include <iostream> #include <string> void main () { std::string s = "abc"; s += "def"; std::cout << s << endl; } #include <iostream> #include <string> using namespace std; void main () { string s = "abc"; s += "def"; cout << s << endl; } abcdef copyright © sbVB http://www.del.ufrj.br/~villas 16 Não misture código com namespace com código sem namespace // certo, todos os headers na versão com namespce #include<iostream> #include<string> using namespace std; // ... // errado, misturando versões de header // com namespace e sem namespace #include<iostream> #include<string.h> using namespace std; // ... copyright © sbVB http://www.del.ufrj.br/~villas Adaptando uma biblioteca existente para uso de namespace std // mylib.h (versão sem namespace) header do usuário inclui #include <iostream.h> header padrão class myClass { public: friend ostream & operator<< (ostream & s, const myClass & obj); }; // main.cpp (versão sem namespace) #include <fstream.h> outros headers #include <string.h> #include "mylib.h" // inclui iostream.h void main () { myClass a; cout << a << endl; } copyright © sbVB padrão http://www.del.ufrj.br/~villas 17 Adaptando uma biblioteca ... (2) // mylib.h (versão adaptada) #ifdef MYLIB_USE_NAMESPACE_STD #include <iostream> using namespace std; #else #include <iostream.h> #endif class myClass { public: friend ostream & operator<< (ostream & s, const myClass & obj); }; // main.cpp, versão usando namespace std // main.cpp, versão sem namespace std #include <fstream> #include <string> #include <fstream.h> #define MYLIB_USE_NAMESPACE_STD #include <string.h> #include "mylib.h" #include "mylib.h" void main () { // daqui para baixo, o programa é igual myClass a; void main () { cout << a << endl; myClass a; // ... cout << a << endl; } // ... http://www.del.ufrj.br/~villas copyright © sbVB } Exemplo de adaptação // overload insersor ostream & operator<< (ostream & stream, const myClass & obj) { stream << obj.m_i << endl << obj.m_d << endl << obj.m_name; class myClass return stream; { } int m_i; // overload extrator double m_d; istream & operator>> VBString m_name; (istream & stream, myClass &obj) public: { myClass() stream >> obj.m_i; { stream >> obj.m_d; m_i = 0; stream >> obj.m_name; m_d = 0; return stream; m_name = "UnNamed"; } }; void main() friend ostream & operator << { (ostream & stream, const myClass &obj); myClass a; friend istream & operator>> cout << a << endl; (istream & stream, myClass &obj); cout << "Entre i d nome : "; }; cin >> a; http://www.del.ufrj.br/~villas copyright © sbVB cout << a << endl; } #include <fstream> #define VBLIB_USE_NAMESPACE_STD #include "vblib.h" 18 RTTI – Run Time Type Identification Identificação de tipo em tempo de execução n Recurso incorporado recentemente ao C++. – Compiladores “velhos” não dão suporte. n Novas palavras reservadas – – – – – typeid dynamic_cast static_cast const_cast reinterpret_cast copyright © sbVB http://www.del.ufrj.br/~villas RTTI – (2) The type of i is int The type of f is float The type of a is class myClass Same type NOT SAME TYPE #include <iostream.h> #include <typeinfo.h> class myClass { /* ... */ }; void printSameType(bool b) { if (b) cout << "Same type" << endl; else cout << "NOT SAME TYPE" << endl; } void main() { int i, j; float f; myClass a; cout << "The type of i is " << typeid(i).name() << endl; cout << "The type of f is " << typeid(f).name() << endl; cout << "The type of a is " << typeid(a).name() << endl; bool sameType = (typeid(i) == typeid(j)); printSameType(sameType); sameType = (typeid(i) == typeid(a)); printSameType(sameType); http://www.del.ufrj.br/~villas copyright © sbVB } 19 RTTI e late bind The type of i is int The type of f is float The type of a is class myClass Same type NOT SAME TYPE #include <iostream.h> #include <typeinfo.h> class myClass { /* ... */ }; void printSameType(bool b) { if (b) cout << "Same type" << endl; else cout << "NOT SAME TYPE" << endl; } void main() { int i, j; float f; myClass a; cout << "The type of i is " << typeid(i).name() << endl; cout << "The type of f is " << typeid(f).name() << endl; cout << "The type of a is " << typeid(a).name() << endl; bool sameType = (typeid(i) == typeid(j)); printSameType(sameType); sameType = (typeid(i) == typeid(a)); printSameType(sameType); http://www.del.ufrj.br/~villas copyright © sbVB } 20