CPP C plus plus versus Java Principais Diferenças • • • • Herança múltipla Destructores e garbage colector Override de operadores Máquina virtual • • • • • • • • • • • Templates e genéricos Referências e ponteiros Métodos virtuais e classes virtuais Conversão implícita de tipos usando construtores Incialização de arrays Listas de inicialização de membros Directivas de pre-processamento Declaration and implementation Bibliotecas (STL) Break e continue sem labels, for each Syntaxe C++ Hello World #include <iostream> using namespace std; void hello() { cout<<“Hello Wordl!”; } int main(){ hello(); } Máquina virtual • O java normalmente corre numa máquina virtual enquanto que o compilador de C++ gera código máquina. Herança múltipla • Uma pessoa pode ser simultaneamente um estudante e um trabalhador. C++ permite herança múltipla. • C++ classe TrabalhadorEstudante: public Trabalhador, public Estudante { … } Pode gerar problemas se houver métodos comuns a trabalhador e a estudante, mas tal pode se resolver por chamadas explicitas do tipo Trabalhador::metodo1(…) ou Estudante::metodo1(…) se a classe estiver a ser utilizada como uma das classes base não há ambiguidade. Herança múltipla • Java Classe TrabalhadorEstudante extends pessoa implements Trabalhador, Estudante{ …. } Obriga e rescrever os métodos de trabalhador e de estudante, embora este possam chamar implementações de classes concretas de trabalhador e de estudante. Ou Classe TrabalhadorEstudante extends pessoa { Trabalhador trabalhador; Estudante estudante; …. } Mas tal não permite redefinir facilmente métodos da classe Trabalhador ou Estudante. Garbage colector e destructores • Em java as variáveis são removidas da memoria pelo garbage colector quando não estão a ser utilizadas. • Em C++ as variáveis locais são automaticamente eliminadas, mas variáveis criadas com o operador new o malloc() tem de ser explicitamente libertadas utilizando o delete ou free() Destrutores File “pessoa.h” class Pessoa { private: nome char*; public: Pessoa(nome char *); ~Pessoa(); char *getNome() {return nome;}; } File “pessoa.cpp” #include “pessoa.h” Pessoa::Pessoa(nome char *){ this->nome = new char[strlen(nome)]; strcpy(this.nome, nome); } Pessoa::~Pessoa(nome char *){ cout<<“destruindo uma Pessoa\n” delete nome; } Destrutores • File “main.cpp” • #include “pessoa.h” main(){ Pessoa pessoa(“Joaquim”); cout<<pessoa.getNome(); cout<<endl; } • Resultado Joaquim destruindo uma Pessoa Overload de operadores String& String::operator+(conts #include <string.h> String &s) conts { String& String *result = new String::operator+=(conts String(this); String &s) { // Copia cada ums dos atributos len+=s.len; // da String. char *p= new char[len+1]; result += s; strcpy(p,str); // Assume que um novo char array // foi alocado. strcat(p,s.str); return *result; delete str; } str=p; return *this; Todos os operadores podem ser redefinidos menos o “::”, “.*”, “.” e “?:” } Código de teste: String aux(“Hello”); aux+=“World\n”; cout<<aux; Código de teste: String aux1(“Hello”); String aux2(“World\n”); cout<< aux1+aux2; Operator overloading • O uso de operadores resulta em código mais compacto. • No entanto código mais compacto é normalmente mais difícil de ler. • Overload de operadores pode levar a código confuso (devido a redefinições não esperadas). • Uma descrição textual é normalmente mais descritiva que um operador. • Overload complica o compilador • Por estas razões, não é suportado pelo java. • No entanto o overload de operadores pode ser útil desde que bem utilizado. Templates e genéricos Template <class Type> Type min(Type a, Type b) { return (a<b)?a:b; } Uma chamada da forma: int a=3, b=4; cout<<min(a, b); Queria uma instância do código da forma: int min(int a, int b) { return (a<b)?a:b; } Uma chamada da forma: double b=3.2, b=4.7; cout<<min(a, b); Queria uma instancia do código da forma: double min(double a, doube b) { return (a<b)?a:b; } Existem duas versões da mesma função ao contrário do mecanismo de apagamento do java. Referências e ponteiros Java • Em java todas as variáveis correspondem a apontadores para objectos com excepção dos tipos primitivos. • C++ os objectos são implementados de forma semelhante a estruturas. Apontador tem de ser criados explicitamente. • Ponteiros em C++ podem ser usados como em C, por exemplo com aritmética de ponteiros. Conta conta = new Conta(100); Conta conta2 = conta; //referencia para conta System.out.println(conta.getSaldo( )); C++ Conta conta(100); Conta conta2 = conta; // cópia membro a membro de conta cout<<conta.getSaldo(); – Ou Conta *conta = new Conta(100); Conta *conta2 = &conta; cout<<(*conta).getSaldo(); Referências C++ (&) • Referências em C++ class Artigo { Revista &revista; Autor &autor; Artigo(Autor &autor, Revista &revista); } Escondem ponteiros mas deixa de ser necessário usar “*”. Exemplo: autor.nome = “João” em vez de (*autor).nome = “João” //autor não é um ponteiro Tem de ser incializadas e depois disso não podem apontar para outros objectos. Tal não acontece com as referências em Java. Ao contrário do java os operadores = e == referem-se ao objecto e não ao ponteiro. int &refval = val; // Ok int &refval; // error Referências java Java C++ class Artigo { class Artigo { Revista revista; Autor autor; Revista *revista; Autor *autor; Artigo(Autor autor, Revista revista) Artigo(Autor *autor, Revista *revista) { { this.autor=autor; this.revista=revista; this->autor=autor; this->revista=revista; } } void println() { System.out.println( autor.nome); System.out.println( revista.nome); } } void println() { cout<<autor->nome; cout<<revista->nome; } } Métodos virtuais Em C++ apenas os métodos com a keyword virtual podem ser redefinidos. • Java class Conta { public final float getSaldo(); public float deposito(); public float levantamento(); } • C++ class Conta { public: float getSaldo(); virtual float deposito(); virtual float levantamento(); } Conversão implícita Em Java conversão implícitas são efectuadas: nos tipos primitivos de char até double; de uma subclasse para uma superclasse. Exemplo: static double somaAAA(double x, double x); int x=3; long z=3; somaAAA(x,z); Ou dump(Conta x); ContaAOrdem conta = new ContaAOrdem(100); Dump(conta); Em C++ quando estas conversões não são possíveis são testadas conversões definidas pelo utilizador baseadas em construtores e operadores de conversão. Exemplo: classe SmallInt { private: int value; public: SamllInt(int x) {value = x;} operator int() {return value;} } extern SmallInt xpto(SmallInt s); void main() { cout<<xpto(34); // converte 34 em SamlInt, e SamlInt em int para enviar para cout } Cast • Em Java os type cast são verificados em tempo real. ContaOrdem extends Conta { /* code */ } Conta conta = new ContaOrdem(100); // Run time checked ContaOrdem contaOrdem = (ContaOrdem)conta; • C++ tem vários tipos de type casts. ContaOrdem: Conta { /* code */ } Conta *conta = new ContaOrdem(100); // C style no run time check Conta *contaOrdem1 = (ContaOrdem)conta; // No run time check ContaOrdem *contaOrdem2 = static_cast<ContaOrdem>(conta); // Run time checked ContaOrdem *contaOrdem3 = dynamic_cast<ContaOrdem>(conta); Arrays: incialização de membros • Em java os membros dos arrays são por defeito incializados a null. • C++ podemos inicializar os arrays com outros objectos. String ar1[] = {“phoenix”,”crane”}; String ar2[] = {String(), String(1024), String(“string”)}; String ar3[] = {1024, String(512)}; Operador delete [] • Se aplicarmos o operador delete a um array apenas o primeiro elemento é libertado da memoria. Para arrays é necessário utilizar o operador delete []. No entanto não é necessário especificar o tamanho do array que é armazenado pelo new. • Exemplo: String aux = new String[100]; ….. delete aux; //errado!!! delete [] aux; //correcto!!! Listas de inicialização de membros • Java classe contaOrdem extends conta { contaOrdem(float v) { super(v); } } é chamado o constructor do super classe como a primeira linha do corpo do constructor. • C++ classe contaOrdem: conta, aplicação { { contaOrdem(float v): conta(v), aplicação() {} } } a chamada aos constructores das super classes é feita numa lista antes do corpo do constructor. Notar que podem ser chamados vários constructores. Listas de inicialização de membros • Java classe Autor { Autor(String n) {…} } …. classe Artigo { Revista revista; Autor autor; Artigo(String autor,…) { autor = new Autor(autor); } • classe Autor { Autor(char *n) {…} } …. classe Artigo { Revista revista; Autor autor; Artigo(char *n,…): autor(n) {} } • } O atributo autor é inicialmente inicializado com null, e só dentro do constructor é que o seu valor final é definido. C++ • O atributo autor não é um ponteiro e portanto não pode ser inicializado a null. Tem de ser inicializado com na lista de incialização de membros. Tal podia ser resolvido declarando autor como um ponteiro. Directivas de pre-processamento • • C++ permite directivas de pre-processamento como no C Exemplo1: #include <iostream> #include “my_header.h” • Exemplo2: #ifndef STRING_H #define STRING_H ….. #endif • Exemplo3: #ifdef win32 ….. #endif #ifdef sun3 ….. #endif Declaração e implementação • No ficheiro “conta.h” • No ficheiro “conta.cpp” #include “conta.h” class Conta{ float valor; float taxa; long numero; void lançaJuros(); void deposito(float x); void levantamento(float x); } void Conta::lançaJuros(){ valor+=valor*taxa; } void Conta::deposito(float x){ valor+=x; } void Conta::levantamento(float x){ valor-=x; } Sintaxe • Uma classe C++ class x: superclasse1, superclasse2 { private: int x; float y; public: rtype método1(args); rtype método2(args); protected: rtype método3(args); }