Peixoto 0 Denunciar post Postado Julho 5, 2011 :( Como vi que o tópico sobre herança foi dado como resolvido, resolvi abrir este para abordar um outro aspecto. Agora veja a nova versão do programa: Do ponto de vista da programação OO, ele está sem erros. Embora sem erros de compilação e rodando, tenho algumas dúvidas sobre a chamada do construtor na herança. Veja. #include <iostream> using namespace std; class Circulo { protected: double raio; static const double PI; private: double Area; double Area_Circulo(); public: Circulo (double r); void Mostra_Area(); }; class Medidas_Circunferencia : public Circulo { private: double Diametro; double Diametro_Circunferencia(); public: Medidas_Circunferencia(double r):Circulo (r){}; void Mostra_Medidas_Circunferencia(); }; Circulo::Circulo(double r) :Area(0) { raio=r; } double Circulo::Area_Circulo() { cout << "Area area do Circulo." << endl; Area=(raio*raio)*PI; // Área do Circulo return (Area); } void Circulo::Mostra_Area() { Area_Circulo(); cout << Area << endl; return; } double Medidas_Circunferencia::Diametro_Circunferencia() { cout << "Diametro da circunferencia:" << endl; Diametro=2*raio; return(Diametro); } void Medidas_Circunferencia::Mostra_Medidas_Circunferencia() { double valor_diametro; valor_diametro=Diametro_Circunferencia(); cout << valor_diametro << endl; return; } const double Circulo::PI=3.1416; //define a variável no //escopo global int main() { Medidas_Circunferencia Medidas(15); Medidas.Mostra_Area(); cout << endl; Medidas.Mostra_Medidas_Circunferencia(); return 0; } Vamos considerar a linha: Medidas_Circunferencia(double r):Circulo (r){} É sabido quando se declara um construtor não padrão na clase-base, é preciso este seja chamado juntamente com o construtor da classe-derivada. Analisando a linha em questão, vemos que r é um atributo de Circulo; então por quê tenho que declarar r no construtor da classe Circunferência, como se tivesse declarando a variável de novo ? ou seja: Medidas_Circunferencia(double r): Obrigado Compartilhar este post Link para o post Compartilhar em outros sites
Renato Utsch 24 Denunciar post Postado Julho 5, 2011 Primeiro, está usando a terminologia errada. r não é um atributo de Circulo, é um parâmetro. O que acontece, pelo que me lembro, é que quando você faz um construtor de classe derivada, você o declara igual a um construtor normal, Medidas_Circunferencia(double r) : Circulo ( r ) {/* Construtor */} e adiciona uma chamada ao construtor da classe base. Medidas_Circunferencia(double r) : Circulo ( r ) {/* Construtor */} Então, em termos mais simples, na hora de construir a classe derivada, você passa um argumento a ela, e esse argumento é passado à classe base. Assim, o r que você põe em Circulo® é a passagem do parâmetro de Medidas_Circunferencia(double r) para o construtor da classe base. Então, se você colocasse: Medidas_Circunferencia(double medida, double raio):Circulo (raio){} Você estaria passando o parâmetro raio de Medidas_Circunferencia como argumento do parâmetro de Circulo. Aí, dentro de Circulo, esse argumento passado pela classe derivada seria chamado de r, como foi declarado em seu protótipo. Entendeu? Abraços :D Compartilhar este post Link para o post Compartilhar em outros sites
Peixoto 0 Denunciar post Postado Julho 6, 2011 :( Confesso, que isso está difícil de entrar na minha cabeça – Embora funcione. Não consigo entender, porquê tenho que passar um parâmetro que é usado na classe circulo para o construtor da classe Circunferência; sendo como já vi em alguns casos, o parâmetro nem é usado na classe derivada. No programa que está sendo discutido, r é usado na derivada, mas há casos em que há uma lista de parâmetros da base que estão sendo chamados na derivada, só porquê são usados na base. Tem como explorar mais estes aspectos ? Obrigado Compartilhar este post Link para o post Compartilhar em outros sites
Renato Utsch 24 Denunciar post Postado Julho 6, 2011 Você sabe a diferença entre parâmetro e argumento? Para entender o que eu disse, é indispensável saber. Um parâmetro, é o que foi declarado no protótipo da função: int func(/* Parâmetros */); E argumento é o valor que supre o parâmetro na hora em que você chama a função: int func(/* Parâmetros */); int main(void) { func(/* Argumentos */); return 0; } /* ... */ Então, como você usaria o construtor da classe básica se você não pode chamar ele pela classe derivada? Não tem jeito de fazer isso na hora de construir a classe. Então o que você faz? Você declara parâmetros na classe derivada, e usa esses parâmetros como argumentos do construtor da classe básica, para construí-la. Agora faz mais sentido? Porque não teria jeito de chamá-la pela classe derivada, então chamamos indiretamente pela classe derivada. Outra coisa: igual você não precisa usar sempre o construtor da classe que você instanciou (um exemplo disso é o <fstream>), você não precisa passar argumentos para a classe básica. Mas isso seria um erro de design, pois se a classe básica não tivesse construtor, como você passaria dados iniciais para ela quando a derivada for declarada? A não ser que todos os elementos da classe básica sejam protected ou public, aí a derivada poderia construí-los de uma vez, mas aí poderia ser erro de design também, já que é bom esconder o máximo que você puder os dados de outras classes, mesmo que sejam derivadas. Então, entendeu o motivo de passar o parâmetro como argumento? Abraços :D Compartilhar este post Link para o post Compartilhar em outros sites
Peixoto 0 Denunciar post Postado Julho 7, 2011 :( Sua explicação foi muito boa. Vamos ver se consigo sintetizar o que você disse: Voltando à linha: Medidas_Circunferencia(double r):Circulo (r){}; Se eu não posso chamar o construtor da base na derivada, é como se Circulo ® se tornasse um argumento a ser passado pelo parâmetro criado em Medidas_Circunferencia(double r). É isso ? é como se o construtor da classe Circulo se tornasse um argumento para o construtor da classe Medidas_Circunferencia(double r) ? Obrigado Compartilhar este post Link para o post Compartilhar em outros sites
Renato Utsch 24 Denunciar post Postado Julho 7, 2011 O contrário. Medidas_Circunferência é a derivada. Você pode ver que o mesmo nome de variável no construtor da classe derivada é utilizado no construtor da classe básica, mas como uma variável, e não definição. Então seria o contrário: O construtor da classe Medidas_Circunferencia(double r) passa seus parâmetros como argumentos do construtor da classe Circulo(double r). Quer uma dica? Mude os noems das variáveis para ver se entende. Chame o de medidas_circunferencia de, sei lá, raiototal e do circulo de raio e veja se consegue adaptar e entender como funciona... Abraços :D Compartilhar este post Link para o post Compartilhar em outros sites
Peixoto 0 Denunciar post Postado Julho 8, 2011 :D Ok, farei este teste. Mesmo porquê, do ponto de vista da matemática, o programa está errado. No tópico anterior, falamos dos rótulos de permissão de acesso (public, private e protected); do ponto de vista das funções-membro e membros de dados. Seria interessante analisaremos as permissões de acesso do ponto de vista da classe. Sei que quando faço: class Derivada:public Base todas as permissões de acesso da base são passadas para derivada, exatamente como na base. mas o que ocorre quando faço: class Derivada:protected Base ou class Derivada:private Base Outro ponto que gostaria de analisar, são as afirmações abaixo, sobre o modo de acesso de uma classe derivada a uma classe derivada. Pincei estas informações, mas parecem confusas. Quando seu programa usa a palavra-chave public para derivar uma classe-base, seu programa pode usar a classe derivada para acessar diretamente os membros públicos dentro da classe-base. No entanto quando você usa a palavra-chave private, seu programa só pode acessar os membros de classe-base por meio dos membros da classe-derivada. Os membros públicos da classe-base, que foram derivados tornam-se privados na derivada. Caso você queira tornar estes membros públicos novamente, deve usar a seguinte sintaxe: Base::função_membro(); ou Base:atributo; Esse artifício não é válido para alterar a situação do objeto, que tenha sido definido como private na classe-base, ou seja: class Base { private: int j; . . } Embora esse seja um expediente interessante, deve ser evitado ao maximo, para não comprometer o encapsulamento da classe. Finalmente quando seu programa usa a palavra-chave protected, a classe que está derivando herda cada um dos membros públicos dentro da classe herdada como membros protegidos, o que permite que a classe derivada acesse os membros da classe-base, permitindo também, que outras classes derivem os membros protegidos. Quando você deriva uma nova classe usando uma ou mais clases-base, é possível que um nome de membro na classe-derivada seja o mesmo que o nome de membro em uma ou mais classes-base. Quando esses conflitos ocorrem, C++ usa o nome de classe derivada. Haverá um momento, que você precisará acessar o membro da classe-base, nesta situação você terá que lançar mão do operador de resolução global (::) . Em todas as formas de herança que foram apresentadas, os membros privados da classe-base são herdados e fazem parte da derivada. Quando declaramos herança com permissão de acesso public; todas permissões de acesso de membros, da classe-base, são repassadas para a classe-derivada. Os membros de dados privados em uma classe derivada, devem ser acessadas por funções-membro criadas para esta finalidade. O que se pode extrair de correto deste texto ? Obrigado Compartilhar este post Link para o post Compartilhar em outros sites
Renato Utsch 24 Denunciar post Postado Julho 8, 2011 Olá! Quando você declara uma classe derivada como public: class Derivada : public Base Todos os membros da classe básica permanecem os mesmos quanto às permissões: os membros públicos da classe base continuam públicos na classe derivada, os membros protected continuam protected na derivada, e os privates da base não são acessados pela derivada. Quando você declara uma classe base como protected em uma derivada: class Derivada : protected Base Os membros públicos da classe base se tornam protected na classe derivada, e, consequentemente, não podem ser acessados de fora da mesma. Agora, sobre os membros protected da classe base, eu não lembro se eles ficam como private ou continuam como protected na classe derivada, isso você teria que testar porque estou em dúvida... Quando você declara uma classe base como private em uma derivada: class Derivada : private Base Tanto os membros public e protected da classe base ficam como membros privados da classe derivada. Sobre aquele quote... estou com muita preguiça de ler ( xD )... veja se entende com a explicação que te dei... se não entender, eu leio e te falo... Abraços :D Compartilhar este post Link para o post Compartilhar em outros sites
Peixoto 0 Denunciar post Postado Julho 9, 2011 :) Eu entendo. O texto está realmente confuso, desanimaa ler, por isso fiz aquelas perguntas específicas.Poderia então apenas comentar este trecho: Caso você queira tornar estes membros públicos novamente, deve usar a seguinte sintaxe: Base::função_membro(); ou Base:atributo; Isto procede ? farei vários testes, começando por onde você tem dúvida. Obrigado Compartilhar este post Link para o post Compartilhar em outros sites
Renato Utsch 24 Denunciar post Postado Julho 9, 2011 Eu não entendi bem o que o autor daquele quote escreveu, mas até onde eu sei não está certo... Você só pode tornar os membros que eram privados na classe básica como públicos mudando o especificador na hora de declarar a classe derivada... class ClassDeriv : private ClassBase {/* ... */ >> class ClassDeriv : public ClassBase {/* ... */ Abraços :D Compartilhar este post Link para o post Compartilhar em outros sites
Peixoto 0 Denunciar post Postado Julho 10, 2011 :o Considere o programa do início do tópico. Nele eu mudei a linha class Medidas_Circunferencia : public Circulo Para class Medidas_Circunferencia : private Circulo A partir deste momento, não pude acessar a função-membro Mostra_Area() via Medidas_Circunferencia como mostrado abaixo int main() { //Circulo Circ(15); //Circ.Mostra_Area(); Medidas_Circunferencia Medidas(15); Medidas.Mostra_Area(); cout << endl; Medidas.Mostra_Medidas_Circunferencia(); return 0; } só via classe base (linha travada por comentário). O erro cai na linha: void Circulo::Mostra_Area() { Veja os erros: D:\Teste\heranca.cpp In function `int main()':44 D:\Teste\heranca.cpp `void Circulo::Mostra_Area()' is inaccessible 76 D:\Teste\heranca.cpp within this context 76 D:\Teste\heranca.cpp `Circulo' is not an accessible base of `Medidas_Circunferencia' Fiz teste com private com classe derivada Se private tira acesso à função-membro da classe Base na Derivada, por que pode-se fazer uma classe derivada privada ? Mudei o rótulo de acesso para: class Medidas_Circunferencia : protected Circulo e as ocorrências foram exatamente as mesmas, sem tirar nem por. Não entendi. Obrigado Compartilhar este post Link para o post Compartilhar em outros sites
Renato Utsch 24 Denunciar post Postado Julho 11, 2011 Velho, vou te admitir: também não '-' O normal de acontecer foi o que te expliquei acima... muito estranho... Faz um outro exemplo ae e testa.. Abraços :D Compartilhar este post Link para o post Compartilhar em outros sites
Peixoto 0 Denunciar post Postado Julho 11, 2011 :( Uma coisa me chama a atenção. Eu uso o DEV-C++ (versão 4.9.9.2) uma IDE para Windows do MingW. O Pessoal diz que esse compilador é muito antigo. Poderia ele não reconhecer certas características da POO ? Tentei rodar um programa que faz sobrecarga de operadores, que peguei na Internet, feito em Visual C++. Tive que adaptar,mesmo assim não roda. Se este pensamento procede, qual outro compilador, mais atual, gratuito com IDE você recomenda ? Não quero acreditar que o DEV-C++ não funcione Com conceitos de POO. Lendo as mensagens de erro; sou levado a entender que o fato da classe derivada ser protected não dá parmesão para funções publicas da base. Obrigado Compartilhar este post Link para o post Compartilhar em outros sites
Renato Utsch 24 Denunciar post Postado Julho 11, 2011 Sim, é verdade. Isso procede muito. O Dev C++ é muito antigo, sua última versão foi pouco tempo depois do standard da C++... Faça o seuginte, baixe o Visual C++ Express Edition 2010 e teste o programa. Eu tenho certeza que vai funcionar como eu disse. Mas, se quer uma solução portável de compilador, não só um que só rode em windows (Visual C++), baixe a última versão do MinGW e utilize o Code::Blocks como IDE. Esqueça o DEV-C++. Para ter uma noção, sua última versão (a 4.9.9.2) foi feita quando ainda utilizavam o Windows 95. Busque compiladores mais recentes. Os mais antigos são cheios de bugs e incoerências, como você pode perceber nele. Ele usa uma versão muito antiga do G++. Abraços :D Compartilhar este post Link para o post Compartilhar em outros sites
Peixoto 0 Denunciar post Postado Julho 12, 2011 :D Mas, se quer uma solução portável de compilador, não só um que só rode em windows (Visual C++), baixe a última versão do MinGW e utilize o Code::Blocks como IDE. Como assim , o Code::Blocks como IDE ? a IDE não Junto do MinGW como no caso do DEV-C++ ? Se não é, como usar a IDE sendo o compilador Separado ? Pelo que entendi, terei que baixar o MinGW e depois o Code::Blocks separadamente. Poderia dar um “BEABA” de como compilar programa usando essas ferramentas ? Portabilidade é um fator, que considero importante. Baixarei essas ferramentas fim de semana, pois ainda uso conexão discada. Obrigado Compartilhar este post Link para o post Compartilhar em outros sites
Renato Utsch 24 Denunciar post Postado Julho 12, 2011 Olá! IDE é aquela janela para editar códigos. Compilador é o software que transforma seu código fonte em código de máquina (executável). O que acontece é que o Dev-C++ é uma IDE, com uma versão bem antiga do MinGW como compilador. Desinstale-o, instale o MinGW utilizando todas as suas opções básicas do instalador (sem mudar caminho de instalação, download last repository packages) e adicione a pasta C:\MinGW\bin no path do seu sistema: Iniciar >> Botão direito em Meu Computador / Computador >> Propriedades (Windows 7 / Vista only) Clique em Configurações Avançadas do Sistema (Windows XP Only) Clique na aba Avançado Clique em Variáveis de Ambiente Em Variáveis do Sistema, selecione a variável PATH e clique em EDITAR (muito cuidado para não remover ou criar nova) Depois do último caracter presente, adicione: ;C:\MinGW\bin clique OK >> OK >> OK Após isso, baixe a última versão do Code::Blocks e instale. Depois configure o compilador como o MinGW (procure no google para aprender a fazer tal ;D) Aí você terá a última versão do GCC disponível para Windows e uma ótima IDE. Entendido? Abraços :D Compartilhar este post Link para o post Compartilhar em outros sites
Peixoto 0 Denunciar post Postado Julho 13, 2011 :D Assim que eu baixar o MInGW volto a escrever. Obrigado Compartilhar este post Link para o post Compartilhar em outros sites
Peixoto 0 Denunciar post Postado Julho 16, 2011 :( Já instalei o MingW. Uso o Windows XP PRO. Fui no menu Iniciar --> propiedade, e não encontrei variável de ambiente. Fui em meu Computador e na área de tratrabalho, propiedade de ambos. Não encontrei variál de ambiente. Que fazer ? Obrigado Compartilhar este post Link para o post Compartilhar em outros sites
Renato Utsch 24 Denunciar post Postado Julho 16, 2011 Olá! Ah, se você não for executar ele da linha de comando não há problema com isso... adicione o caminho dele ao Code::Blocks e o utilize como compilador... Aí teste... Abraços :D Compartilhar este post Link para o post Compartilhar em outros sites
Peixoto 0 Denunciar post Postado Julho 17, 2011 :o Fui na página http://www.codeblocks.org/downloads/26 que disponibiliza uma versão do codeblocks, sem MingW(já que este está instalado na maquina). Durante o processo de instalação não encontrei escrito a opção MingW. Como configurar para MingW após a instalação do codeblocks ? Obrigado Compartilhar este post Link para o post Compartilhar em outros sites