LINGUAGEM DE PROGRAMAC¸ ˜AO C++ HIERARQUIA DE CLASSES Roberto S. Bigonha UFMG 01 de abril de 2009 & % HIERARQUIA DE CLASSES & % ' $ HIERARQUIA DE CLASSES HERANC¸ A SIMPLES
• heran¸ca ´e uma t´ecnica para construir novas classes, chamadas de classes derivadas, a partir das j´a existentes, ditas classes base • heran¸ca permite o re´uso do comportamento de uma classe
• a classe derivada herda todas as caracter´ısticas de sua classe base e pode adicionar novas caracter´ısticas
• heran¸ca permite construir hierarquia de classes
• heran¸ca permite classificar tipos da mesma forma que tipos classificam valores
• heran¸ca estabelece as rela¸c˜oes de especializa¸c˜ao e generaliza¸c˜ao entre as classes base e derivadas
• membros da classe base podem ser redefinidos na classe derivada
' $
HIERARQUIA DE CLASSES
DEFINIC¸ ˜AO UMA CLASSE BASE
class Time {
int hours, minutes, seconds; public:
Time(int hr, int min, int sec){
hours = hr; minutes = min; seconds = sec; }
void display(){
cout << hours << ’:’ << minutes << ’:’ << seconds; }
' $
HIERARQUIA DE CLASSES
DEFININDO CLASSE DERIVADA
enum timezone { gmt, est, cst, mst, pst }; char *TZ[] = {"GMT","EST","CST","MST","PST"}; class TimeZone : public Time {
|
timezone zone; +--- default ´e private public:
TimeZone(int hr, int min, int sec, timezone zn) : Time(hr,min,sec){zone=zn;} timezone getZone( ) {return zone;}
void display(){Time::display();cout << ’ ’ << TZ[zone];} };
c++/rsb 4
& %
' $
HIERARQUIA DE CLASSES
USANDO BASE E DERIVADA
int main() { Time tm(23, 15, 45); tm.display(); cout << ’\n’; TimeZone tz(10, 26, 0, est); tz.display(); } SAIDA: 23:15:45 10:26:0 EST c++/rsb 5 & % ' $
CONSTRUTORAS DE CLASSE DERIVADA
' $
CONSTRUTORAS DE CLASSE DERIVADA
CONSTRUTORAS DE CLASSE DERIVADA
• Quando um objeto de classe derivada ´e declarado, a fun¸c˜ao
construtora da base ´e executada e, em seguida, executa-se a fun¸c˜ao construtora da derivada
• A lista de parˆametros da construtora da derivada deve conter os parˆametros da construtora da base
• A chamada da construtora da base deve ser indicada explicitamente como abaixo
class TimeZone : public Time{ ...
TimeZone(int hr, int min, int sec, timezone zn)
: Time(hr, min, sec) { ... }; ...
CONSTRUTORAS DE CLASSE DERIVADA ...
• A lista de argumentos da construtora da classe base deve aparecer na declara¸c˜ao da construtora da derivada
• A chamada `a construtora da classe base deve estar associada a declara¸c˜ao da fun¸c˜ao e n˜ao do prot´otipo
class TimeZone : public Time{ ...
TimeZone(int hr, int min, int sec, timezone zn); ...
}
TimeZone::TimeZone(int hr,int min,int sec,timezone zn) :Time(hr,min,sec){ ...
}
c++/rsb 8
& %
CLASSE DERIVADA DE BASE DERIVADA ...
• Se n˜ao houver chamada expl´ıcita de construtora, a construtora sem parˆametros ´e chamada
class A { int x; public:
A( ):x(100) { }
int getX( ){return x;} };
class B: public A { int y;
public:
B(){ y = 1000; }
int gety( ) {return y;} };
int main(){ B b;
printf("x= %d y= %d\n", b.getX(), b.gety()); }
Sa´ıda: 100 1000
c++/rsb 9
& %
' $
CONSTRUTORAS DE CLASSE DERIVADA
CLASSE DERIVADA DE BASE DERIVADA ...
inline int adjust(int hour){
return hour > 12 ? hour - 12 :(hour == 0 ? 12 : hour); }
inline char makeampm(int hour){ return hour < 12 ? ’a’ : ’p’; }
' $
CONSTRUTORAS DE CLASSE DERIVADA
CLASSE DERIVADA DE BASE DERIVADA...
class DispTime : public TimeZone { char ampm;
public:
DispTime(int hr, int min, int sec, timezone zn)
: TimeZone(adjust(hr), min, sec, zn){ ampm = makeampm(hr);
}
void display() { Time::display();
cout << ’ ’ << ampm << ’m’; << ’ ’ << TZ[getZone()]; }
' $
CONSTRUTORAS DE CLASSE DERIVADA
CLASSE DERIVADA DE BASE DERIVADA...
int main(){ DispTime dt(21, 42, 12, pst); dt.display(); return 0; } SAIDA: 9:42:12 pm PST c++/rsb 12 & % ' $
CONSTRUTORAS DE CLASSE DERIVADA
CONSTRUTORA PRIVADA E SUBCLASSES
class A{ public: int x; A( ): x(10){ } int f( ){return x;} }; class B: public A { }; int main( ){ B b; printf("x = %d", b.f()); } Sa´ıda: x = 10; class A { int x; A( ): x(10){ } public: int f( ){return x;} }; class B: public A { }; int main( ) { B b; // Erro aqui printf("x = %d", b.f()); } A e B compilam normalmente Erro na compila¸c˜ao de B b c++/rsb 13 & % ' $
CONSTRUTORAS DE CLASSE DERIVADA
PONTEIROS E CLASSES DERIVADAS OU BASE
• Um apontador para uma classe base pode apontar para um objeto de uma classe dela derivada
• O tipo com o qual o ponteiro ´e declarado ´e o seu tipo est´atico e o tipo do objeto apontado ´e o seu tipo dinˆamico
• Os componentes n˜ao-virtuais da classe declarada para o ponteiro continuam acess´ıveis atrav´es dele, mesmo quando anulados (redefinidos)
int main(){
DispTime dt(21, 42, 12, pst);
Time *tp = &dt; TimeZone *zp = &dt; DispTime *dp = &dt; tp->display(); zp->display(); dp->display();
return 0; }
SAIDA: 9:42:12 9:42:12 PST 9:42:12 pm PST
' $
CONSTRUTORAS DE CLASSE DERIVADA
RESOLUC¸ ˜AO DE ESCOPO GLOBAL
int main(){
DispTime dt(21, 42, 12, pst); DispTime *dp = &dt; dp ->display(); // usa display de DispTime cout << ’\n’; // SAIDA: 9:42:12 pm PST dt.display(); cout << ’\n’; // SAIDA: 9:42:12 pm PST dp ->TimeZone::display(); // usa display de TimeZone cout << ’\n’; // SAIDA: 9:42:12 PST dt.TimeZone::display(); // SAIDA: 9:42:12 PST cout << ’\n’;
dp ->Time::display(); // usa display de Time cout << ’\n’; // SAIDA: 9:42:12 dt.Time::display(); // SAIDA: 9:42:12 cout << ’\n’;
REFERˆENCIAS A CLASSE BASE E DERIVADA
• Uma referˆencia a uma classe base pode ser iniciada com um objeto de classe dela derivada
• O tipo com o qual a referˆencia ´e declarada ´e o seu tipo est´atico e o tipo do objeto referido ´e o seu tipo dinˆamico
• Os componentes n˜ao-virtuais da classe declarada para a referˆencia continuam acess´ıveis atrav´es dela, mesmo quando anulados
(redefinidos) int main(){
DispTime dt(21, 42, 12, pst);
Time& tp = dt; TimeZone& zp = dt; DispTime& dp = dt; tp.display(); zp.display(); dp.display();
return 0;
} // SAIDA: 9:42:12 9:42:12 PST 9:42:12 pm PST
c++/rsb 16
& %
ESCOPO DOS MEMBROS DE CLASSE
• membros p´ublicos (public) de uma classe s˜ao acess´ıveis a todo o programa
• membros privados (private) de uma classe somente s˜ao acess´ıveis a membros fun¸c˜oes da classe
• membros privados da classe base n˜ao s˜ao acess´ıveis `a classe derivada • membros protegidos(protected) da classe base s˜ao acess´ıveis a
membros de classes derivadas (filhas, netas, ...), mas privados para o resto do programa
c++/rsb 17
& %
' $
CONSTRUTORAS DE CLASSE DERIVADA
ESCOPO DOS MEMBROS DA CLASSE BASE
•class B : private A { ... } ou class B : A { ... }:
os membros p´ublicos e protegidos de uma classe base s˜ao membros privados da classe derivada de classe base private
•class B : public A { ... }:
os membros p´ublicos e protegidos de uma classe base s˜ao,
respectivamente, membros p´ublicos e protegidos da classe derivada de classe base public
•class B : protected A { ... }:
os membros p´ublic ou protected da classe base s˜ao membros protected da classe derivada de classe base protected.
' $
CONSTRUTORAS DE CLASSE DERIVADA
ESCOPO DOS MEMBROS DE CLASSE...
class X {
int priv;// private por default protected: int prot; public: int publ; void m(); } void X::m() { priv := 1; // OK prot := 2; // OK publ := 3; // OK }
' $
CONSTRUTORAS DE CLASSE DERIVADA
ESCOPO DOS MEMBROS DE CLASSE...
void Y::g( ) {
priv := 1; // ERRO: priv ´e privado
prot := 2; // OK: prot ´e protected e g ´e membro de // classe derivada
publ := 3; // OK: publ ´e publico }
void f(Y* p) {
p-> priv := 1; // ERRO:priv ´e privado
p-> prot := 2; // ERRO:prot ´e protected, mas f n~ao // ´e friend ou membro de X ou Y p-> publ := 3; // OK: publ ´e public
}
c++/rsb 20
& %
' $
FUNC¸ ˜OES VIRTUAIS
& %
' $
Fun¸c˜oes Virtuais
FUNC¸ ˜OES VIRTUAIS
• Fun¸c˜ao virtual ´e aquela definida numa classe base e que espera ser anulada por uma fun¸c˜ao em uma classe derivada como o mesmo nome e tipos de parˆametros
• Um apontador para uma classe base pode apontar para um objeto de uma classe dela derivada
• Os componentes virtuais acess´ıveis da classe s˜ao os componentes do objeto apontado, independentemente do tipo do apontador que chama o componente
• Virtual somente a partir do ponto na hierarquia em que foi declarada virtual
• Uma vez virtual, sempre virtual
• Tipo polim´orfico ´e tipo com fun¸c˜oes virtuais
' $
Fun¸c˜oes Virtuais
CLASSE COM FUNC¸ ˜OES VIRTUAIS
class Time {
int hours, minutes, seconds; public:
Time(int hr, int min, int sec){
hours = hr; minutes = min;seconds = sec; }
virtual void display(){
cout << hours << ’:’ << minutes << ’:’ << seconds; }
CLASSE COM FUNC¸ ˜OES VIRTUAIS...
enum timezone { gmt, est, cst, mst, pst }; char *TZ[] = {"GMT","EST","CST","MST","PST"}; class TimeZone : public Time {
timezone zone; public:
TimeZone(int hr,int min,int sec,timezone zn) :Time(hr,min,sec){ zone = zn;
}
virtual void display() { // virtual opcional
Time::display(); cout << ’ ’ << TZ [zone]; }
};
c++/rsb 24
& %
CLASSE COM FUNC¸ ˜OES VIRTUAIS...
inline int adjust(int hour) {
return hour > 12 ? hour - 12 :(hour == 0 ? 12 : hour); }
inline char makeampm(int hour) { return hour < 12 ? ’a’ : ’p’; }
c++/rsb 25
& %
' $
Fun¸c˜oes Virtuais
CLASSE COM FUNC¸ ˜OES VIRTUAIS...
class DispTime : public TimeZone { char ampm;
public:
DispTime(int hr,int min,int sec,timezone zn)
: TimeZone(adjust(hr),min,sec,zn){ampm=makeampm(hr);} void display(){ Time::display(); cout << ’ ’ << ampm << ’m’; cout << ’ ’ << TZ [zone]; } }; ' $
Fun¸c˜oes Virtuais
REFERˆENCIA A UMA FUNC¸ ˜AO VIRTUAL
' $
Fun¸c˜oes Virtuais
ANULANDO O ANULAMENTO int main(){ DispTime dt(21, 42, 12, pst); Time& tp = dt; TimeZone& zp = dt; DispTime& dp = dt; tp.Time::display(); cout << ‘\n’; zp.TimeZone::display(); cout << ‘\n’; dp.display(); } SAIDA: 9:42:12 9:42:12 PST 9:42:12 pm PST c++/rsb 28 & % ' $
Fun¸c˜oes Virtuais
LIGAC¸ ˜AO DINˆAMICA DE M´ETODOS I
class A {
public: int i; A( ){i = 10;}
private: virtual void increment( ) { i++; } public: virtual void display( ) {
increment( ); printf("i = %d\n", i); }
};
class B: public A {
public: int i; B() {i = 20;} public: void increment( ){ i++; } };
int main( ) {
B* x = new B( ); x->display( ); // Sa´ıda: i = ? }
c++/rsb 29
& %
' $
Fun¸c˜oes Virtuais
LIGAC¸ ˜AO DINˆAMICA DE M´ETODOS I ...
class A {
public: int i; A( ){i = 10;}
private: virtual void increment( ) { i++; } public: virtual void display( ) {
increment( ); printf("i = %d\n", i); }
};
class B: public A {
public: int i; B() {i = 20;} public: void increment( ){ i++; } };
int main( ) {
B* x = new B( ); x->display( ); // Sa´ıda: i = 10 }
' $
Fun¸c˜oes Virtuais
LIGAC¸ ˜AO DINˆAMICA DE M´ETODOS II
class A {
public: int i; A( ){i = 10;}
private: void increment( ) { i++; } public: virtual void display( ) {
increment( ); printf("i = %d\n", i); }
};
class B: public A {
public: int i; B() {i = 20;} public: void increment( ){ i++; } };
int main( ) {
LIGAC¸ ˜AO DINˆAMICA DE M´ETODOS II...
class A {
public: int i; A( ){i = 10;}
private: void increment( ) { i++; } public: virtual void display( ) {
increment( ); printf("i = %d\n", i); }
};
class B: public A {
public: int i; B() {i = 20;} public: void increment( ){ i++; } };
int main( ) {
B* x = new B( ); x->display( ); // Sa´ıda: i = 11 }
c++/rsb 32
& %
LIGAC¸ ˜AO DINˆAMICA DE M´ETODOS III
class A {
public: int i; A( ){i = 10;}
private: void increment( ) { i++; } public: virtual void display( ) {
increment( ); printf("i = %d\n", i); }
};
class B: public A {
public: int i; B() {i = 20;} private: void increment( ){ i++; } };
int main( ) {
B* x = new B( ); x->display( ); // Sa´ıda: i = ? }
c++/rsb 33
& %
' $
Fun¸c˜oes Virtuais
LIGAC¸ ˜AO DINˆAMICA DE M´ETODOS III...
class A {
public: int i; A( ){i = 10;}
private: void increment( ) { i++; } public: virtual void display( ) {
increment( ); printf("i = %d\n", i); }
};
class B: public A {
public: int i; B() {i = 20;} private: void increment( ){ i++; } };
int main( ) {
B* x = new B( ); x->display( ); // Sa´ıda: i = 11 }
' $
Fun¸c˜oes Virtuais
LIGAC¸ ˜AO DINˆAMICA DE M´ETODOS IV
class A {
public: int i; A( ){i = 10;}
private: virtual void increment( ) { i++; } public: virtual void display( ) {
increment( ); printf("i = %d\n", i); }
};
class B: public A {
public: int i; B() {i = 20;} private: void increment( ){ i++; } };
int main( ) {
' $
Fun¸c˜oes Virtuais
LIGAC¸ ˜AO DINˆAMICA DE M´ETODOS IV
class A {
public: int i; A( ){i = 10;}
private: virtual void increment( ) { i++; } public: virtual void display( ) {
increment( ); printf("i = %d\n", i); }
};
class B: public A {
public: int i; B() {i = 20;} private: void increment( ){ i++; } };
int main( ) {
B* x = new B( ); x->display( ); // Sa´ıda: i = 10 }
c++/rsb 36
& %
' $
Fun¸c˜oes Virtuais
RESPEITO `A ENCAPSULAC¸ ˜AO
• Cada classe deve cuidar somente de seus dados locais
• Subclasses nunca devem ter acesso direto a dados herdados • Acesso a dados das superclasses devem ser via os canais
competentes
• Altera¸c˜oes em dados internos da superclasse n˜ao devem afetar a corre¸c˜ao de suas subclasses
• Ad´agio romano[Apeles]: Ne sutor ultra crepˇıdam
c++/rsb 37
& %
' $
Fun¸c˜oes Virtuais
RESPEITO `A ENCAPSULAC¸ ˜AO ...
class Hora { int h, m, s; public:
Hora(int hr, int min, int sec) { ... }
void display(){cout << h << ’:’ << m << ’:’ << s;} }
class HoraLocal : public Hora { String local;
public:
HoraLocal(int h,int m,int s,String local):Hora(h,m,s){ this.local = local;
}
void display(){Hora::display();cout<< ’ ’ << local; } }
' $
Fun¸c˜oes Virtuais
CLASSES ABSTRATAS
• Uma classe abstrata ´e uma que especifica uma ou mais fun¸c˜oes virtuais puras
• Fun¸c˜ao virtual pura n˜ao tem corpo
Exemplo: virtual void display( ) = 0;
• Fun¸c˜oes virtuais puras devem ser definidas por alguma subclasse da classe abstrata
• Subclasses que n˜ao definem as fun¸c˜oes virtuais nulas herdadas tamb´em s˜ao abstratas
FUNC¸ ˜AO VIRTUAL PURA
•Time ´e uma classe abstrata
class Time {
int hours, minutes, seconds; public:
Time(int hr, int min, int sec) {
hours = hr; minutes = min; seconds = sec; }
void displayTime() {
cout << hours << ’:’ << minutes << ’:’ << seconds; }
virtual void display() = 0;
};
enum timezone { gmt, est, cst, mst, pst };
char *TZ[] = { "GMT", "EST", "CST","MST", "PST" };
c++/rsb 40
& %
FUNC¸ ˜AO VIRTUAL PURA...
class TimeZone : public Time { timezone zone;
public:
TimeZone(int h,int m,int s,timezone z):Time(h,m,s) { zone = z; } void display(); }; void TimeZone::display() { displayTime(); cout << ’ ’ << TZ [zone]; } c++/rsb 41 & % ' $
Fun¸c˜oes Virtuais
FUNC¸ ˜AO VIRTUAL PURA...
int main() { TimeZone dt(21, 42, 12, pst); Time& tp = dt; tp.display(); cout << ’\n’; dt.display(); return 0; } SAIDA: 21:42:12 PST 21:42:12 PST ' $
Fun¸c˜oes Virtuais
FUNC¸ ˜OES VIRTUAIS E DERIVADAS M ´ULTIPLAS
class Date {// classe abstrata protected:
int mo, da, yr; public:
Date(int m, int d, int y){mo = m; da = d; yr = y;} virtual void display() = 0;
};
class NumDate : public Date { public:
' $
Fun¸c˜oes Virtuais
FUNC¸ ˜OES VIRTUAIS E DERIVADAS M ´ULTIPLAS...
class AlphaDate : public Date { public:
AlphaDate(int m, int d, int y) : Date(m,d,y) { ... } void display();
};
void AlphaDate::display() { static char *mos[] = {
"Janeiro","Fevereiro","Marco","Abril", "Maio","Junho", "Julho","Agosto", "Setembro","Outubro","Novembro", "Dezembro"
};
cout << mos[Date::mo-1] << ’ ’ << da << ", " << yr+1900; }
c++/rsb 44
& %
' $
Fun¸c˜oes Virtuais
FUNC¸ ˜OES VIRTUAIS E DERIVADAS M ´ULTIPLAS...
int main() { NumDate nd(7,29,41); AlphaDate ad(11,17,41); Date& dt1 = nd; Date& dt2 = ad; dt1.display(); cout << ’\n’; dt2.display(); } SAIDA: 7/29/41 Novembro 17, 1941 c++/rsb 45 & % ' $
Fun¸c˜oes Virtuais
CLASSES DE UMA EMPRESA
class OrgEntity { char name[25]; int employee_count; public:
OrgEntity(char *s,int ec) {
strcpy(name,s); employee_count=ec; }
int number_employees() { return employee_count; }
char *org_name() { return name; } virtual int office_party() = 0; };
' $
Fun¸c˜oes Virtuais
CLASSES DE UMA EMPRESA ...
class Company : public OrgEntity { public:
Company(char *s,int ec) : OrgEntity(s,ec){ } virtual int office_party() {
return 100; }
CLASSES DE UMA EMPRESA
class Division : public Company { public:
Division(char *s,int ec) : Company(s,ec) { } virtual int office_party() {
return 75; }
};
c++/rsb 48
& %
CLASSES DE UMA EMPRESA ...
class Department : public Division { public:
Department(char *s, int ec): Division(s, ec) { } virtual int office_party() {
return 50; } }; c++/rsb 49 & % ' $
Fun¸c˜oes Virtuais
PROGRAMA DE ORC¸ AMENTO
void budget(OrgEntity& oe); int main() {
Company company("Bilbo Software, Inc.", 35); Division div("Aplicacoes Verticais", 12); Department dept("Departamento Medico", 4); // Polimorfismo budget(company); budget(div); budget(dept); } ' $
Fun¸c˜oes Virtuais
PROGRAMA DE ORC¸ AMENTO...
void budget(OrgEntity& oe){
cout << "\n--- Relatorio de Orcamento --\n"; cout << oe.org_name();
cout << " $" << oe.number_employees() * oe.office_party(); cout << ’\n’;
} SAIDA:
' $
FUNC¸ ˜AO DESTRUIDORA
& %
' $
Fun¸c˜ao Destruidora
FUNC¸ ˜OES DESTRUIDORAS DA BASE E DERIVADA
• Quando um objeto de uma classe derivada sai do escopo de
execu¸c˜ao, a fun¸c˜ao destruidora da classe derivada ´e executada e, em seguida, a fun¸c˜ao destruidora para a classe base ´e executada
• No caso de delete p, onde p ´e ponteiro para a classe base, a
destruidora da base ser´a executada, mesmo se p aponta para objeto da classe derivada
• Quando a fun¸c˜ao destruidora for virtual, todas as destruidoras abaixo dela na hierarquia s˜ao virtuais, e o compilador chama a destruidora correta
• Fun¸c˜oes construtoras n˜ao podem ser virtuais
c++/rsb 53
& %
' $
Fun¸c˜ao Destruidora
CHAMANDO DESTRUIDORA DA BASE
class Company { char *name; public:
Company(char *s){
name = new char[strlen(s+1)]; strcpy(name, s);
}
~Company( ) {
cout << "Destruidor C"; delete name; }
void printOrgName() { cout << name; } };
' $
Fun¸c˜ao Destruidora
CHAMANDO DESTRUIDORA DA BASE ...
class Division : public Company { char *manager;
public:
CHAMANDO DESTRUIDORA DA BASE...
int main(){
Company *companies[3];
companies[0] = new Company("Casa de Software SJT");
companies[1] = new Division("Pequenos Sistemas", "Carolina"); companies[2] = new Division("Grandes Sistemas", "Patricia"); ... // processa os objetos da companhia
for (int i = 0; i < 3; i++) {
delete companies[i]; // nem sempre a destruidora correta } return 0; } SAIDA: Destruidor C Destruidor C Destruidor C c++/rsb 56 & % DESTRUIDORA VIRTUAL class Company { char *name; public: Company(char *s){
name = new char[strlen(s+1)]; strcpy(name, s); }
virtual ~Company( ) {
cout << "Destruidor C";delete name; }
void printOrgName() { cout << name; } }; c++/rsb 57 & % ' $ Fun¸c˜ao Destruidora DESTRUIDORA VIRTUAL
class Division : public Company { char *manager;
public:
Division(char *s, char *mgr) : Company(s){
manager=new char[strlen(mgr+1)];strcpy(manager, mgr); } ~Division(){ cout<<"Destruidor D"; delete manager; } }; ' $ Fun¸c˜ao Destruidora DESTRUIDORA VIRTUAL int main(){ Company *companies[3];
companies[0] = new Company("Casa de Software SJT");
companies[1] = new Division("Pequenos Sistemas", "Carolina"); companies[2] = new Division("Grandes Sistemas", "Patricia"); ...
' $ HERANC¸ A M ´ULTIPLA & % ' $ Heran¸ca M´ultipla HERANC¸ A M ´ULTIPLA
• Heran¸ca m´ultipla ´e a capacidade de uma classe derivada ter mais de uma classe base
• Uma derivada de duas bases:
class FileStamp:public Time, public Date{ ...
};
• A construtora de uma classe derivada de bases m´ultiplas deve especificar os argumentos para as fun¸c˜oes construtoras de todas as classes base
FileStamp(char * f,int m,int d,int y,int hr,int mn,int sc) : Time(hr, mn, sc), Date(m, d, y){ ... } • As construtoras s˜ao executadas na ordem especificada
c++/rsb 61
& %
' $
Heran¸ca M´ultipla
USANDO HERANC¸ A M ´ULTIPLA
class Time {
int hours, minutes, seconds; public:
Time(int h, int m, int s) {
hours = h; minutes = m; seconds = s; }
virtual void display() {
cout << hours << ’:’ << minutes << ’:’ << seconds; }
};
' $
Heran¸ca M´ultipla
USANDO HERANC¸ A M ´ULTIPLA
class Date {
int month, day, year; public:
Date(int m, int d, int y){
month = m; day = d; year = y; }
virtual void display(){
cout << month << ’/’ <<day << ’/’ <<year; }
USANDO HERANC¸ A M ´ULTIPLA...
class FileStamp1 : public Time, public Date { char filename[15];
public:
FileStamp1(char *fn,int m,int d,int y,int h,int min,int s) :Time(h,min,s),Date(m, d, y){strcpy(filename,fn);} void display(); }; void FileStamp1::display(){ cout << filename << ’ ’; Date::display(); cout << ’ ’; Time::display(); } c++/rsb 64 & %
USANDO HERANC¸ A M ´ULTIPLA...
int main(){ FileStamp1 fs("DADOS",4,6,90,13,32,27); fs.display(); } SAIDA: DADOS 4/66/90 13:32:27 c++/rsb 65 & % ' $ Heran¸ca M´ultipla
AMBIGUIDADES COM HERANC¸ A M ´ULTIPLA
class FileStamp2 : public Time, public Date { char filename[15];
public:
FileStamp(char *fn,int m,int d,int y,int h,int min,int s) :Time(h,min,s),Date(m, d, y){strcpy(filename,fn);} }; int main(){ FileStamp2 fs("DADOS",4,6,90,13,32,27); fs.display(); // Erro fs.Time::display(); // OK fs.Date::display(); // OK } ' $ Heran¸ca M´ultipla
A COMPLEXIDADE DE HERANC¸ A M ´ULTIPLA
class A {public: int x;}
class B {public: virtual int h( ){ ... } int x, y; } class C: public A, public B {
public:
' $
Heran¸ca M´ultipla
A COMPLEXIDADE DE HERANC¸ A M ´ULTIPLA...
c++/rsb 68
& %
' $
Heran¸ca M´ultipla
A COMPLEXIDADE DE HERANC¸ A M ´ULTIPLA...
c++/rsb 69
& %
' $
Heran¸ca M´ultipla
A COMPLEXIDADE DE HERANC¸ A M ´ULTIPLA...
' $
Heran¸ca M´ultipla
A COMPLEXIDADE DE HERANC¸ A M ´ULTIPLA...
c++/rsb 72
& %
A COMPLEXIDADE DE HERANC¸ A M ´ULTIPLA...
c++/rsb 73
& %
' $
CLASSES BASE VIRTUAIS
' $
Classes Base Virtuais
CLASSES BASE VIRTUAIS
• Com heran¸ca m´ultipla, uma classe derivada pode ter mais de uma ocorrˆencia de uma das bases
• Observe a ambig¨uidade de referˆencia a x em D: class A { ... int x; ... }
class B : public A { ... x ... } class C : public A { ... x ... }
class D : public B, public C { ... x(?) ... }
• Solu¸c˜ao: classe base A deve ser declarada virtual: class A { ... int x; ... }
class B : public virtual A { ... x ... } class C : public virtual A { ... x ... } class D : public B, public C { ... x ... }
' $
Classes Base Virtuais
BASE VIRTUAL I
class A {public: int x;}; class B: public virtual A { }; class C: public virtual A { }; class D: public B, public C { public:
D() {x = 1000;}; // OK };
int main(int argc, char *argv[]){ D d; printf("x = %d\n", d.x); } Sa´ıda: x = 1000 c++/rsb 76 & % ' $
Classes Base Virtuais
BASE VIRTUAL II
class A {public: int x;}; class B: public virtual A { }; class C: public A { }; class D: public B, public C { public:
D() {x = 1000;}; // ERRO: AMB´IGUO };
int main(int argc, char *argv[]){ D d; printf("x = %d\n", d.x); } c++/rsb 77 & % ' $
Classes Base Virtuais
BASE VIRTUAL III
class A {public: int x;}; class B: public A { }; class C: public A { }; class D: public B, public C { public:
D() {x = 1000;}; // ERRO: AMB´IGUO };
int main(int argc, char *argv[]){ D d;
printf("x = %d\n", d.x); }
' $
Classes Base Virtuais
BASE VIRTUAL IV
class A {public: int x;}; class B: public virtual A{ }; class C: public virtual A{ };
class D: public virtual B, public virtual C, public virtual A{ public: D(){ A::x = 10;
B::x = 11; C::x = 13; x = 13;
} };
int main(int argc, char *argv[]){ D d;
printf("d.A::x=%d,d.B::x=%d,d.C::x=%d,d.D::x = %d\n", d.A::x,d.B::x,d.C::x,d.D::x);
BASE VIRTUAL V
class A {public: int x;}; class B: public virtual A{ }; class C: public virtual A{ };
class D: public virtual B, public virtual C, public A{ public: D(){ A::x = 10; // ERRO: A ´e base amb´ıgua
B::x = 11; C::x = 13;
x = 13; // ERRO: refer^encia amb´ıgua }
};
int main(int argc, char *argv[]){ D d; printf("d.A::x=%d,d.B::x=%d,d.C::x=%d,d.D::x = %d\n", d.A::x,d.B::x,d.C::x,d.D::x); } // c++/rsb 80 & % BASE VIRTUAL VI
class A {public: int x;}; class B: public virtual A{ }; class C: public virtual A{ };
class D: public B, public C, public virtual A{ public: D(){ A::x = 10;
B::x = 11; C::x = 13; x = 13;
} };
int main(int argc, char *argv[]){ D d;
printf("d.A::x=%d,d.B::x=%d,d.C::x=%d,d.D::x = %d\n", d.A::x,d.B::x,d.C::x,d.D::x);
} // Sa´ıda: d.A:x=13, d.B::x=13, d.C::x=13, d.D::x = 13
c++/rsb 81
& %
' $
Classes Base Virtuais
BASE VIRTUAL VII
class A {public: int x;}; class B: public virtual A{ }; class C: public A{ };
class D: public B, public C, public virtual A{ public: D(){ A::x = 10; // ERRO: A ´e base amb´ıgua
B::x = 11; C::x = 13;
x = 13; // ERRO: refer^encia amb´ıgua }
};
int main(int argc, char *argv[]){ D d;
printf("d.A::x=%d,d.B::x=%d,d.C::x=%d,d.D::x = %d\n", d.A::x,d.B::x,d.C::x,d.D::x);
}
' $
Classes Base Virtuais
USO DE BASE VIRTUAL
struct Item{
char name[25]; int cost; };
class Product : public virtual Item { int qty_sold;
public:
Product(char *nm, int qty, int cst){
qty_sold = qty; strcpy(name, nm); cost = cst; }
' $
Classes Base Virtuais
USO DE BASE VIRTUAL...
class Service : public virtual Item { int manhours;
public:
Service(char *nm, int mh, int cst){
manhours = mh; strcpy(name, nm); cost = cst; }
virtual void display(){cout << manhours;} };
class Installation : public Product, public Service { public:
Installation(char *nm, int qty, int hrs, int cst) : Product(nm, qty, cst), Service(nm, hrs, cst) { } void display();
};
c++/rsb 84
& %
' $
Classes Base Virtuais
USO DE BASE VIRTUAL...
void Installation::display(){
cout << "\nInstalados "; Product::display(); cout << ’ ’ << name << "es" << "\nTempo: "; Service::display();
cout << " horas"; << "\nCusto: $" << cost; } int main(){ Installation inst("refrigeradores", 2,3,75); inst.display(); return 0; }
SAIDA: Instalados 2 refrigeradores Tempo: 3 horas Custo: $75 c++/rsb 85 & % ' $ COMPILAC¸ ˜AO DE CLASSES ' $ COMPILAC¸ ˜AO DE CLASSES
IMPLEMENTAC˜AO DE MEMBROS FUNC¸ ˜OES
• Membros Fun¸c˜oes N˜ao-Virtuais
–referˆencias `as fun¸c˜oes resolvidas em tempo de compila¸c˜ao –n˜ao podem ser alterados
–n˜ao fazem parte do leiaute dos objetos, portanto na inicializa¸c˜ao de estruturas devem ser ignorados
• Membros Fun¸c˜oes Virtuais
–para cada classe ´e criada uma tabela de fun¸c˜oes virtuais (VMT) –todo objeto passa a ter o endere¸co da VMT da classe
–referˆencias `as fun¸c˜oes resolvidas em tempo de execu¸c˜ao, via VMT –n˜ao podem ser alterados
HERANC¸ A SIMPLES E FUNC¸ ˜OES VIRTUAIS
class A {
public: int a;
virtual void f (int); virtual void g (int); virtual void h (int); };
class B : public A {
public: int b; virtual void g (int); };
class C : public B {
public: int c; virtual void h (int); };
c++/rsb 88
& %
LEIAUTE DOS OBJETOS
+---+ | int a | vtbl: | vptr --+--->+---+ | int b | | &A::f | | int c | | &B::g | +---+ | &C::h | +---+ C* pc = new C; pc -> g(2); ---> (*(pc->vptr[1]))(pc,2); c++/rsb 89 & % ' $ COMPILAC¸ ˜AO DE CLASSES
HERANC¸ A M ´ULTIPLA E FUNC¸ ˜OES VIRTUAIS
class A {
public: virtual void f ( ){..}; } class B : { public: virtual void f ( ){ ... g(); ...}; virtual void g ( ){ ... }; }; this+deltaB class C : public A, public B { |
public: virtual void f ( ){ ... g(); ...}; };
' $
' $
Verifica¸c˜ao de Tipos Dinˆamicos
dynamic cast
• A fun¸c˜ao dynamic cast<T*>(p) verifica o tipo do objeto apontado por p e retorna:
–um ponteiro do tipo T*, se tipo dinˆamico de p for T* ou ponteiro para um tipo que tem T como base ´unica
–um ponteiro do tipo T*, se o tipo est´atico de p for T* ou D*, onde
T ´e uma base da classe D. Neste caso, o uso de dynamic cast n˜ao ´e necess´ario, pois o compilador pode determinar a validade da convers˜ao
–0, se nenhum dos casos anteriores se aplica ou se p==0
• O prop´osito do dynamic cast ´e cuidar da convers˜ao em situa¸c˜oes em que o compilador n˜ao tem meios de fazˆe-la
•dynamic cast n˜ao permite viola¸c˜ao acidental de prote¸c˜ao de base privada ou protegida
c++/rsb 92
& %
' $
Verifica¸c˜ao de Tipos Dinˆamicos
dynamic cast ...
class A { ... } class B { ... }
class C: public A, protected B { ... }; class D: public C { ... };
void f(C* p) {
A* q = p; // OK
A* r = dynamic_cast<A*>(p); // OK, mas desnecess´ario B* t = p; // Erro: B ´e base protegida B* u = dynamic_cast<B*>(p) // ok, mas faz u = 0
D* z = dynamic_cast<D*>(p) // ok, se p apontar para objeto // do tipo D, sen~ao faz z = 0 }
c++/rsb 93
& %
' $
Verifica¸c˜ao de Tipos Dinˆamicos