Jump to content

[C++] Ajuda: Problemas com construtor de classes


merlin3000
 Share

Recommended Posts

Já mexo com o c++ há algum tempo.. mas só recentemente peguei novamente (e para não parar espero) sem ser para trabalhos no c++ e para aprender mais um pouco sobre alocação de memória, classes e outras coisas. Resolvi fazer uma classe simples de manipulação de arrays de caracteres tipo a string.h (muito mais simples claro).

Mas pelo caminho deparei-me com um problema. O código necessário para o exemplo é este.

-----------

main.cpp

#include <iostream>
#include "CDstring.h"

using namespace std;

int main()
{
    CDstring a( "Texto 1" );
    CDstring f = a;
    CDstring l = "Texto 2";

return 0;
}

CDstring.h

#ifndef _CDstring_h_
#define _CDstring_h_

class CDstring
{
   int text_size(char *text, char lim='\0');

public:

   char *string;
   int last;


   CDstring();
   CDstring(CDstring &str);
   CDstring(char *text, char lim='\0');
   ~CDstring();
};
#endif

-----------

O erro acontece na linha a CDstring l = "Texto 2"; quando tento compilar.. aparece:

main.cpp    10  error: no matching function for call to `CDstring::CDstring(CDstring)'

CDstring.h  16  note: candidates are: CDstring::CDstring(char*, char)

CDstring.h  15  note:                          CDstring::CDstring(CDstring&)

main.cpp    10  error: initializing temporary from result of `CDstring::CDstring(char*, char)'

Não consigo perceber porque é que ele vê o "Texto 2" como um objecto do tipo CDstring! Se o construtor CDstring::CDstring(CDstring &str) não existir (e consequentemente a linha CDstring f = a comentada) funciona bem.. CDstring l = "Texto 2" chama o construtor CDstring(char *text, char lim='\0')..

A questão é que no VC++ Express (estou a programar no gcc com o Code::Blocks(Nightly Build 12-12-06)) funciona tudo bem, corre como seria esperado. Pelo menos como eu esperava que corresse lol...

Alguém me podia dar uma ajudinha? Não consigo perceber o que se passa já vi alguns tutoriais e a inicialização por "ObjectoX obx = Valor" devia ser permitida (descobri isso por acidente quando fiz o overloading do operador =  ?

Criar é Divertido

Link to comment
Share on other sites

Não sei se já tinha sido desejado, mas bem-vindo ao fórum =)

A ideia com que fico é que o compilador fica "um pouco confuso" porque não tens um construtor que receba só um char*, e quando inicializas uma CDstring com = ele procura por esse construtor e não encontra. Para tirar as dúvidas, experimenta alterar o construtor

CDstring(char *text, char lim='\0');

para

CDstring(char *text);

e vê se compila bem, o que vai acontecer quase de certeza.

Se assim for, para contornar o problema, utiliza 2 construtores:

CDstring(char *text, char lim);
CDstring(char *text);

em que a implementação do 2º é simplesmente

CDstring(char *text) {
CDstring(text, '\0');
}

Desaparecido.

Link to comment
Share on other sites

Já alguém tinham dito algo no post de apresentação lol mas Obrigado e obrigado pela resposta.

Em principio não seria disso porque o construtor tem o parametro lim pré-definido para '\0'. A linha  CDstring a( "Texto 1" ); funciona sem problemas. Mas tentando:

main.cpp:10: error: no matching function for call to `CDstring::CDstring(CDstring)'

CDstring.h:17: note: candidates are: CDstring::CDstring(const char*, char)

CDstring.h:16: note:                CDstring::CDstring(char*)

CDstring.h:15: note:                CDstring::CDstring(CDstring&)

main.cpp:10: error:  initializing temporary from result of `CDstring::CDstring(const char*, char)'

Apenas acrescentou mais ao construtor aos candidatos.. não tou a ver porque seja.

Criar é Divertido

Link to comment
Share on other sites

Mas nesse caso também não seria preciso declarar o operador = para que isto funcionasse? CDstring f = a; ... eu sei que neste caso não é. Pelo que tenho lido isto é o funcionamento normal para um copy constructor.

Mas inda só vi exemplos em que se usa o mesmo tipo de dados.. será que se for diferente é preciso o overload do operador =?

E a minha dúvida principal é que se o constructor CDstring(CDstring &str); não existir CDstring l = "Texto 2"; chama o constructor certo.

Em VC++ mesmo com os 2 constructores cada um é chamado na sua vez sem problemas.

Criar é Divertido

Link to comment
Share on other sites

Ok.. noutro exemplo:

#include <iostream>

using namespace std;

class T
{
public:
    char data_[10];
    T(char *i) { cout<<"T(char *i)"<<endl; }
    T(T&) { cout<<"T(T&)"<<endl; }
};
int
main(int, char**)
{
    T t1("we"); // OK
    T t2 = "we"; // OK
    T t3(t2); //OK
    T t4 = t1; //OK
}

Aqui dá o mesmo erro mas se pusermos em vez de T(T&) { cout<<"T(T&)"<<endl; }

tivermos ... T(const T&) { cout<<"T(T&)"<<endl; } já funciona. Eu não percebo muito bem o funcionamento do const. Alguém me podia dizer o que é que ele ali faz de diferente? Isto aplicado ao exemplo anterior também funciona. Embora depois aja um erro dentro da função em si... mas o importante é que entra onde deve.

Criar é Divertido

Link to comment
Share on other sites

Aqui dá o mesmo erro mas se pusermos em vez de T(T&) { cout<<"T(T&)"<<endl; }

tivermos ... T(const T&) { cout<<"T(T&)"<<endl; } já funciona. Eu não percebo muito bem o funcionamento do const. Alguém me podia dizer o que é que ele ali faz de diferente? Isto aplicado ao exemplo anterior também funciona. Embora depois aja um erro dentro da função em si... mas o importante é que entra onde deve.

O const diz ao compilador que o argumento T não é modificado dentro da função, se tentares alterar algum argumento definido como const, o compilador deveria dar erro.

Sobre o teu código anterior (o primeiro), eu testei no VC++ 6.0 e funcionou perfeitamente...  😛

Cumpr. bk@ero  👍

Link to comment
Share on other sites

Confirma-se. Dá o mesmo erro com o gcc em Linux. E aqui encontramos isto:

Copy constructor syntax

The copy constructor takes a reference to a const parameter. It is const to guarantee that the copy constructor doesn't change it, and it is a reference because a value parameter would require making a copy, which would invoke the copy constructor, which would make a copy of its parameter, which would invoke the copy constructor, which ...

Desaparecido.

Link to comment
Share on other sites

Nesse caso tenho que fazer o overload do operador =. Mas isso eu sei que funciona porque tenho já o fiz. (não pus no exemplo porque no VC++ ele ia buscar o construtor certo e no GCC quando não existe o construtor CDstring(CDstring &str); ele também chama o construtor correcto e em nenhum caso tenta chamar o operador = , ele queixa-se é de supostamentenão existir o construtor certo).

Em VC++ ele não cria um construtor chama o construtor CDstring(char *text, char lim='\0');

Em GCC por alguma razão queixa-se se não tiver const no construtor CDstring(CDstring &str); mas o estranho (para mim :/ pelo meno ) é que ele queixa-se na linha CDstring l = "Texto 2"; que chama o outro construtor. Não percebo porque é que interfere.

Criar é Divertido

Link to comment
Share on other sites

O comportamento é de prever olhando para os primeiros erros que apresentaste.

O compilador GCC na inicialização tem de chamar um construtor independentemente se existir o operador=, porque isto não é um construtor.

Logo o = na inicialização refere-se a um construtor que tenha só um parametro. O unico existe não tem const e logo não está correcto.

Agora porque é que ele não considera o construtor que tem o 2º parametro por defeito parece ser um comportamento caracteristico do GCC que difere do VC++. Qual é o comportamento correcto? Só vendo no standart c++

Na minha opinião o VC++ parece ter um comportamento mais logico, visto que existe uma opção para resolver o problema.

Embora ache que o facto de mantermos as coisas explicitas pode retirar confusão em código complexo. logo nesse aspecto o GCC ajuda a manter o código mais explicito.

Basicamente o código T a = x; é um alias de T a(x);

Para não existir confusão é sempre melhor usar T a(x);

Aqui há coisa de 2 anos fazia umas malhas de croché, depois fartei-me e fui para informática!

Link to comment
Share on other sites

O mal é que mesmo que exista o construtor CDstring(char *text); ele dá o mesmo erro como tá num exemplo ali em cima. O que tava a tentar descobrir é porqe é que usar o = na declaração dá erro mas chamar no estilo de Objecto Ob("Texto" ) funciona bem.

Deve existir alguma diferença eu é que não tou a ver qual lol

Criar é Divertido

Link to comment
Share on other sites

A diferença está em que ao usares o = ao construir o objecto, o compilador procura pelo construtor por cópia, que exige que o parâmetro passado seja const. Ao chamares o construtor explicitamente e passares um objecto que não é const já não há essa restrição. É a mesma diferença entre este código:

	CDstring a( "Texto 1" );
CDstring f(a);

e este:

	const CDstring a( "Texto 1" );
CDstring f(a);

em que o 2º troço só funciona se tiveres um construtor que receba um const CDString, e não funciona se só tiveres um construtor que receba um CDString não const.

Desaparecido.

Link to comment
Share on other sites

Ok.. acho que começo a perceber.. desculpem lá se tou a ser chato.

O que eu não entendo é o que é que o CDstring = "Texto 1" tem a ver com o construtor CDstring(CDstring &str). Se esse construtor não exisitir ele chama o construtor CDstring(char *text, char lim='\0') e se tiver o const no em  CDstring(CDstring &str) também chama CDstring(char *text, char lim='\0'). Se ele sabe qual chamar porque precisa que exista um construtor com const que ele não vai usar.

E por exemplo: CDstring f = a; isto também não deveria dar o mesmo problema? FUnciona direito mesmo sem ter const no construtor cópia.

Criar é Divertido

Link to comment
Share on other sites

Olhando de novo para o código, e em particular para este erro:

main.cpp    10  error: initializing temporary from result of `CDstring::CDstring(char*, char)'

quando fazes

    CDstring l = "Texto 2";

o que acontece é que o compilador está a criar uma CDstring temporária com o construtor que recebe um char*, e depois cria o objecto l por cópia dessa CDstring temporária... por isso é que se está a queixar do construtor por cópia.

Agora o porquê de isso acontecer... imagino que seja por não teres um construtor que receba exclusivamente um char*. Podes, como disse antes, experimentar esse código sem o construtor CDstring(char *test, char lim='\0'), e no seu lugar dois construtores: um CDstring(char *test, char lim) com exactamente o mesmo código do anterior, e outro simplesmente

CDstring(char *test){ CDstring(test, '\0'); }

para ver o que acontece então. Se estiver certo, será chamado este último construtor, que irá chamar o outro.

Já do CDstring f = a; não se queixa porque existe um construtor que recebe um parâmetro do tipo de a. CDstring f = a; não chama o "construtor por cópia", chama um construtor que receba um parâmetro do tipo de a.

Já agora, por definição, o construtor por cópia recebe um parâmetro const. Se o parâmetro não for const, não é um construtor por cópia.

Desaparecido.

Link to comment
Share on other sites

Obrigado pela explicação TheDark.

Com o construtor CDstring(char *test) e sem o const no CDstring(CDstring &str) simplesmente adiciona mais um construtor aos candidatos. Com o const funciona bem. Mas acho que percebi a ideia. Se declarar com o = com um tipo que não seja o do objecto em si ele chama o construtor cópia certo?

Mas no debug passo a passo não devia passar por lá? Quando se faz debug ele simplesmente entra no construtor  CDstring(char *text, char lim='\0'), mas não se vê a passar no construtor cópia. E quando o construtor CDstring(CDstring &str) não existe? Ele funciona bem, ele consegue trabalhar sem esse construtor?

Criar é Divertido

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.