estou estudando C++ e estou com uma dúvida referente a polimorfismo e
métodos abstratos.
Para tal, peço para que analisem o código abaixo, pois não consigo
entender o que estou fazendo errado: tenho uma classe abstrata chamada
Shape e duas classes derivadas: Circle e Square, cujas declarações se
encontram abaixo:
class Circle : public Shape {
public:
char* getNome() {
return "Circle";
}
};
class Square : public Shape {
public:
char* getNome() {
return "Square";
}
};
A dúvida na realidade surge no meu método main:
int main(int argc, char **argv) {
Shape *shape[2];
Dúvida 1: por que o código abaixo é inválido?
shape[0] = new Square();
shape[1] = new Circle();
No caso, como eu deveria reescrevê-lo?
Dúvida 2: o código abaixo será executado? Em caso negativo, o que está
errado?
cout << shape[0]->getNome() << endl;
cout << shape[1]->getNome() << endl;
return 1;
> -----Mensagem original----- > De: Kico Weissmann
> Dúvida 1: por que o código abaixo é inválido? > shape[0] = new Square(); > shape[1] = new Circle(); > No caso, como eu deveria reescrevê-lo?
Não tem nada de errado com estas linhas, é um ponteiro para uma classe base recebendo um objeto derivado.
> Dúvida 2: o código abaixo será executado? Em caso negativo, o que está > errado? > cout << shape[0]->getNome() << endl; > cout << shape[1]->getNome() << endl;
> Faltou declarar as funções das classes derivadas como virtual:
> class Circle : public Shape {
> public:
> virtual char* getNome() {
> return "Circle";
> }};
> class Square : public Shape {
> public:
> virtual char* getNome() {
> return "Square";
> }
> };
> Acho que é isso...
Quando a classe base está definida como virtual, não faz diferença se
as derivadas estão declaradas como virtuais ou não.
-x-
Vendo as dúvidas de um iniciante, é possível ver que C++ é realmente
uma linguagem complicada de se aprender, pois é cheia de detalhes.
Neste exemplo ainda seria importante explicar que o destructor deveria
ser virtual, e como fazer o gerenciamento da memoria alocada.
Ainda assim, provavelmente, a explicação não entraria no detalhe das
exceções nem do detalhe do comportamento do new. (new [] delete []
etc)
Então seria preciso explicar o RAII os containers da STL e os smart
pointers.
> Faltou declarar as funções das classes derivadas como virtual:
> class Circle : public Shape { > public: > virtual char* getNome() { > return "Circle"; > } > }; > class Square : public Shape { > public: > virtual char* getNome() { > return "Square"; > } > };
> Acho que é isso...
Se você declarar na classe base que um método é virtual, este método continuará sendo considerado virtual mesmo que não tenha a palavra chave "virtual" nas classes derivadas. Ou seja, "virtual" é opcional nas classes derivadas pois o compilador já foi instruído a implementar a virtualização. No entando é bom colocar o "virtual" nas classes derivadas também para documentar este fato.
Claro que é bom colocar, depois tu pega um código um pouco maior e tem que
ficar lembrando que é virtual. -.- pelo amor de deus deixa a preguiça de
lado né!
> Se você declarar na classe base que um método é virtual, este método
> continuará sendo considerado virtual mesmo que não tenha a palavra
> chave "virtual" nas classes derivadas. Ou seja, "virtual" é opcional
> nas classes derivadas pois o compilador já foi instruído a
> implementar a virtualização. No entando é bom colocar o "virtual"
> nas classes derivadas também para documentar este fato.
Eu só perguntei isto porque nos livros de C++ que eu li até agora dizem que
só é necessário declarar na classe base.
Então, quando você me disse para incluir a palavra chave virtual nas classes
filhas, achei que tivesse me enganado a respeito, e que esta palavra-chave
também deveria ser incluida nas classes filhas, entende?
2009/7/7 Thiago Diniz da Silveira <thiagods...@gmail.com>
> Claro que é bom colocar, depois tu pega um código um pouco maior e tem que
> ficar lembrando que é virtual. -.- pelo amor de deus deixa a preguiça de
> lado né!
>> Se você declarar na classe base que um método é virtual, este método
>> continuará sendo considerado virtual mesmo que não tenha a palavra
>> chave "virtual" nas classes derivadas. Ou seja, "virtual" é opcional
>> nas classes derivadas pois o compilador já foi instruído a
>> implementar a virtualização. No entando é bom colocar o "virtual"
>> nas classes derivadas também para documentar este fato.
> Se você declarar na classe base que um método é virtual, este método > continuará sendo considerado virtual mesmo que não tenha a palavra > chave "virtual" nas classes derivadas. Ou seja, "virtual" é opcional > nas classes derivadas pois o compilador já foi instruído a > implementar a virtualização. No entando é bom colocar o "virtual" > nas classes derivadas também para documentar este fato.
Então, eu disse "Acho" por que justamente tive um problema semelhante, que eu não lembro qual foi a solução, mas se não me engano foi com algo assim: cupostamente deveria funcionar de forma X mas o compilador fazia Y. Não tenho certeza mesmo, só dei um palpite de intrometido mesmo. ;-)
> > Se você declarar na classe base que um método é virtual, este método
> > continuará sendo considerado virtual mesmo que não tenha a palavra
> > chave "virtual" nas classes derivadas. Ou seja, "virtual" é opcional
> > nas classes derivadas pois o compilador já foi instruído a
> > implementar a virtualização. No entando é bom colocar o "virtual"
> > nas classes derivadas também para documentar este fato.
> Então, eu disse "Acho" por que justamente tive um problema semelhante, que
> eu
> não lembro qual foi a solução, mas se não me engano foi com algo assim:
> cupostamente deveria funcionar de forma X mas o compilador fazia Y. Não
> tenho
> certeza mesmo, só dei um palpite de intrometido mesmo. ;-)
> > Se você declarar na classe base que um método é virtual, este método
> > continuará sendo considerado virtual mesmo que não tenha a palavra
> > chave "virtual" nas classes derivadas. Ou seja, "virtual" é opcional
> > nas classes derivadas pois o compilador já foi instruído a
> > implementar a virtualização. No entando é bom colocar o "virtual"
> > nas classes derivadas também para documentar este fato.
> Então, eu disse "Acho" por que justamente tive um problema semelhante, que
> eu
> não lembro qual foi a solução, mas se não me engano foi com algo assim:
> cupostamente deveria funcionar de forma X mas o compilador fazia Y. Não
> tenho
> certeza mesmo, só dei um palpite de intrometido mesmo. ;-)
>> > Se você declarar na classe base que um método é virtual, este método
>> > continuará sendo considerado virtual mesmo que não tenha a palavra
>> > chave "virtual" nas classes derivadas. Ou seja, "virtual" é opcional
>> > nas classes derivadas pois o compilador já foi instruído a
>> > implementar a virtualização. No entando é bom colocar o "virtual"
>> > nas classes derivadas também para documentar este fato.
>> Então, eu disse "Acho" por que justamente tive um problema semelhante, que
>> eu
>> não lembro qual foi a solução, mas se não me engano foi com algo assim:
>> cupostamente deveria funcionar de forma X mas o compilador fazia Y. Não
>> tenho
>> certeza mesmo, só dei um palpite de intrometido mesmo. ;-)
O que observei foi o seguinte. Na minha matriz, que inicialmente eu pré
carregava como ponteiros para a classe basica, eu a populava tal como no
código abaixo.
No entanto, toda vez que ia executar um método abstrato nas classes filhas,
dava erro de execução.
Ao verificar o tipo armazenado na matriz usando o operador idtype, o que
verifiquei é que lá estavam instâncias da classe base, e não das classes
filhas.
Como consequencia, toda vez que eu chamava o método abstrato, este não
estava implementado na instancia armazenada e eu tinha um erro de execução.
Esta é a razão pela qual eu achei que o código estava inválido de alguma
forma. Como pode ver, nada a ver com trabalhos de faculdade ou coisas do
gênero.
Na realidade, é mais relacionado a um hobby que iniciei neste final de
semana e cujo resultado estou documentando no meu blog:
http://www.itexto.net/devkico/?p=419
Sendo assim, pode ficar tranquilo :) : não é mais um estudante pedindo para
outros fazerem seu trabalho de faculdade, mas sim alguém que DE FATO está
tentando se aprofundar na linguagem C++ e que acreditou que talvez a
comunidade brasileira poderia lhe auxiliar neste processo.
Um abraço
2009/7/8 Pedro Lamarão <pedro.lama...@member.fsf.org>
> O que observei foi o seguinte. Na minha matriz, que inicialmente eu pré
> carregava como ponteiros para a classe basica, eu a populava tal como no
> código abaixo.
> No entanto, toda vez que ia executar um método abstrato nas classes filhas,
> dava erro de execução.
> Ao verificar o tipo armazenado na matriz usando o operador idtype, o que
> verifiquei é que lá estavam instâncias da classe base, e não das classes
> filhas.
> Como consequencia, toda vez que eu chamava o método abstrato, este não
> estava implementado na instancia armazenada e eu tinha um erro de execução.
> Esta é a razão pela qual eu achei que o código estava inválido de alguma
> forma. Como pode ver, nada a ver com trabalhos de faculdade ou coisas do
> gênero.
> Na realidade, é mais relacionado a um hobby que iniciei neste final de
> semana e cujo resultado estou documentando no meu blog:
> http://www.itexto.net/devkico/?p=419
> Sendo assim, pode ficar tranquilo :) : não é mais um estudante pedindo para
> outros fazerem seu trabalho de faculdade, mas sim alguém que DE FATO está
> tentando se aprofundar na linguagem C++ e que acreditou que talvez a
> comunidade brasileira poderia lhe auxiliar neste processo.
> Um abraço
> 2009/7/8 Pedro Lamarão <pedro.lama...@member.fsf.org>
>> On 6 jul, 20:01, Kico Weissmann <loboweissm...@gmail.com> wrote:
>> > A dúvida na realidade surge no meu método main:
>> > Dúvida 1: por que o código abaixo é inválido?
>> > shape[0] = new Square();
>> > shape[1] = new Circle();
>> > No caso, como eu deveria reescrevê-lo?
>> Boa pergunta.
>> Por que você acha que esse código é inválido?
>> Qual é o problema, o compilador está falhando a compilação?
>> Perguntas do tipo "o código está certo? em caso negativo, bla bla bla"
>> são perguntas de trabalho de casa da faculdade.
On 8 jul, 16:51, Henrique Lobo Weissmann <loboweissm...@gmail.com>
wrote:
> O que observei foi o seguinte. Na minha matriz, que inicialmente eu pré
> carregava como ponteiros para a classe basica, eu a populava tal como no
> código abaixo.
> No entanto, toda vez que ia executar um método abstrato nas classes filhas,
> dava erro de execução.
> Ao verificar o tipo armazenado na matriz usando o operador idtype, o que
> verifiquei é que lá estavam instâncias da classe base, e não das classes
> filhas.
> Como consequencia, toda vez que eu chamava o método abstrato, este não
> estava implementado na instancia armazenada e eu tinha um erro de execução.
Acho que percebi a questão.
É algo do C++ que eu ainda não parei pra aprender completamente.
Nas classes derivadas de Shape, não há uma função declarada com a
palavra-chave "virtual".
Por esse motivo, o compilador deve estar considerando que essas
classes não são polimórficas, e não produzindo coisas como um ponteiro
para vtable e coisas assim.
Por acaso a presença de um "virtual" na função sobrescrita nas classes
derivadas resolve o problema?
Em geral esse tipo de situação não acontece porque invariavelmente o
destruidor é "virtual".
Henrique, estava escrevendo um exemplo enorme com código fonte compilável e tudo para servir de exemplo, quando me ocorreu que a tua dúvida é bem mais simples.
Você deve estar tentando algo como:
cout << typeid(shape[0]).name() << endl;
E está obtendo "Shape *" como resposta.
Tenta usar: cout << typeid(*shape[0]).name() << endl; // Repare no asterisco antes de shape.
ai que tá Eric, eu fazia exatamente como você mostrou, com o * na frente, e
o resultado obtido ainda era do tipo Shape.
Estou no trabalho agora, porém assim que chegar em casa irei copiar o código
fonte para que vocês dêem uma olhada, porque realmente o resultado que
obtive é muito estranho.
> Henrique, estava escrevendo um exemplo enorme com código fonte compilável e
> tudo para servir de exemplo, quando me ocorreu que a tua dúvida é bem mais
> simples.
> Você deve estar tentando algo como:
> cout << typeid(shape[0]).name() << endl;
> E está obtendo "Shape *" como resposta.
> Tenta usar:
> cout << typeid(*shape[0]).name() << endl; // Repare no asterisco antes de
> shape.
> ai que tá Eric, eu fazia exatamente como você mostrou, com o * na frente, e
> o resultado obtido ainda era do tipo Shape.
> Estou no trabalho agora, porém assim que chegar em casa irei copiar o
> código fonte para que vocês dêem uma olhada, porque realmente o resultado
> que obtive é muito estranho.
>> Henrique, estava escrevendo um exemplo enorme com código fonte compilável
>> e tudo para servir de exemplo, quando me ocorreu que a tua dúvida é bem mais
>> simples.
>> Você deve estar tentando algo como:
>> cout << typeid(shape[0]).name() << endl;
>> E está obtendo "Shape *" como resposta.
>> Tenta usar:
>> cout << typeid(*shape[0]).name() << endl; // Repare no asterisco antes de
>> shape.
Pessoal, bom dia! Estou muito perto de concluir meu projeto mas estou atolado em um detalhe.
Escrevi uma aplicação usando as api do alsa para gravar e reproduzir som. Junto, eu estou implementando uma analize de fourier, usando a biblioteca fftw: http://www.fftw.org/!
Ai que está o problema. É utilizado um ring buffer tanto para leitura quanto para escrita. Eu preciso fazer com que esse IN sejá um ponteiro para meu ring buffer. Algêm pode me dar uma ajuda.
** in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * 44100); out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * 44100);*
* in = audiobuf; *********(isso aqui que eu não consigo fazer)*************
header(rtype, name); set_params();
* p = fftw_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
* do { for (cur = count; cur > 0; cur -= r) { c = (cur <= chunk_bytes) ? cur : chunk_bytes; c = c * 8 / bits_per_frame; if ((size_t)(r = pcm_read(audiobuf, c)) != c) * * break; r = r * bits_per_frame / 8; if ((err = write(fd, audiobuf, r)) != r) { perror(name); exit(EXIT_FAILURE); } if (err > 0) fdcount += err; } } while (rtype == FORMAT_RAW && !timelimit);
> Pessoal, bom dia!
> Estou muito perto de concluir meu projeto mas estou atolado em um detalhe.
> Escrevi uma aplicação usando as api do alsa para gravar e reproduzir
> som. Junto, eu estou implementando uma analize de fourier, usando a
> biblioteca fftw: http://www.fftw.org/!
> Ai que está o problema. É utilizado um ring buffer tanto para leitura
> quanto para escrita.
> Eu preciso fazer com que esse IN sejá um ponteiro para meu ring buffer.
> Algêm pode me dar uma ajuda.
> Estou muito perto de concluir meu projeto mas estou atolado em um > detalhe.
> Escrevi uma aplicação usando as api do alsa para gravar e reproduzir > som. Junto, eu estou implementando uma analize de fourier, usando a > biblioteca fftw: http://www.fftw.org/!
> Ai que está o problema. É utilizado um ring buffer tanto para leitura > quanto para escrita. > Eu preciso fazer com que esse IN sejá um ponteiro para meu ring buffer. > Algêm pode me dar uma ajuda.
Qual o compilador e versão você está usando? Eu rodei no g++ 4.3.2 e
funcionou perfeitamente,
segue abaixo o código (com algumas modificações para evitar warnings e
com uma destrutora virtual):
> estou estudando C++ e estou com uma dúvida referente a polimorfismo e
> métodos abstratos.
> Para tal, peço para que analisem o código abaixo, pois não consigo
> entender o que estou fazendo errado: tenho uma classe abstrata chamada
> Shape e duas classes derivadas: Circle e Square, cujas declarações se
> encontram abaixo:
> ai que tá Eric, eu fazia exatamente como você mostrou, com o * na frente, e
> o resultado obtido ainda era do tipo Shape.
> Estou no trabalho agora, porém assim que chegar em casa irei copiar o
> código fonte para que vocês dêem uma olhada, porque realmente o resultado
> que obtive é muito estranho.
> Henrique, estava escrevendo um exemplo enorme com código fonte compilável e
>> tudo para servir de exemplo, quando me ocorreu que a tua dúvida é bem mais
>> simples.
>> Você deve estar tentando algo como:
>> cout << typeid(shape[0]).name() << endl;
>> E está obtendo "Shape *" como resposta.
>> Tenta usar:
>> cout << typeid(*shape[0]).name() << endl; // Repare no asterisco antes de
>> shape.