merlin3000 Posted December 15, 2006 at 10:42 AM Report #70647 Posted December 15, 2006 at 10:42 AM 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
TheDark Posted December 16, 2006 at 01:23 AM Report #70813 Posted December 16, 2006 at 01:23 AM 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.
merlin3000 Posted December 16, 2006 at 08:29 AM Author Report #70820 Posted December 16, 2006 at 08:29 AM 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
Halaster Posted December 18, 2006 at 10:03 PM Report #71271 Posted December 18, 2006 at 10:03 PM Para inicializares o objecto com o sinal de igual, creio que terás de definir o operador = na classe, pois caso contrário o compilador não sabe o que é que tu queres fazer com o sinal. Penso eu de que... ?
merlin3000 Posted December 19, 2006 at 03:31 AM Author Report #71309 Posted December 19, 2006 at 03:31 AM 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
merlin3000 Posted December 19, 2006 at 04:27 AM Author Report #71314 Posted December 19, 2006 at 04:27 AM 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
brink@ero Posted December 19, 2006 at 06:52 PM Report #71413 Posted December 19, 2006 at 06:52 PM 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 👍
merlin3000 Posted December 20, 2006 at 05:37 PM Author Report #71585 Posted December 20, 2006 at 05:37 PM Pois em VC++ eu também corro perfeitamente. O mal é que dá o tal erro no GCC e não sei porquê. Acho que percebi o const mas.. porque faz difenreça neste caso então? não devia ser opcional para mim usar ou não? ali é como se ele o exigisse. Criar é Divertido
shumy Posted December 20, 2006 at 05:52 PM Report #71588 Posted December 20, 2006 at 05:52 PM Correctamente o construtor copia deve ser sempre const. Não é lógico ao fazer uma cópia mudar o que se está a copiar. E parece que o gcc valida isso. Aqui há coisa de 2 anos fazia umas malhas de croché, depois fartei-me e fui para informática!
TheDark Posted December 20, 2006 at 11:55 PM Report #71674 Posted December 20, 2006 at 11:55 PM Confirma-se. Dá o mesmo erro com o gcc em Linux. E aqui encontramos isto: Copy constructor syntaxThe 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.
merlin3000 Posted December 21, 2006 at 01:08 AM Author Report #71681 Posted December 21, 2006 at 01:08 AM Hmm.. OK.. Obrigado pelas respostas.. já começo a a perceber. Mas porque é que se não puser o const no construtor que leva o objecto em si, não dá erro na linha que deve chamar esse contrustor mas sim na linha que chamava o construtor que recebe um char* ? Criar é Divertido
pem Posted December 21, 2006 at 05:36 AM Report #71696 Posted December 21, 2006 at 05:36 AM Isto é para o primeiro exemplo. O VC++ consegue criar alguns construtores, o que me parece que te esta a acontecer é que quando fazes CDstring l = "Texto 2"; é diferente de fazer isto CDstring l (Texto 2)";. Exprimenta fazer esta alterçao ao codigo CDstring l; l=("texto 2"); diz o que acontece.
merlin3000 Posted December 21, 2006 at 02:46 PM Author Report #71752 Posted December 21, 2006 at 02:46 PM 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
shumy Posted December 21, 2006 at 03:10 PM Report #71754 Posted December 21, 2006 at 03:10 PM 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!
merlin3000 Posted December 23, 2006 at 04:28 PM Author Report #72130 Posted December 23, 2006 at 04:28 PM 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
TheDark Posted December 24, 2006 at 03:51 AM Report #72217 Posted December 24, 2006 at 03:51 AM 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.
merlin3000 Posted December 27, 2006 at 11:28 PM Author Report #72832 Posted December 27, 2006 at 11:28 PM 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
TheDark Posted December 28, 2006 at 01:49 AM Report #72857 Posted December 28, 2006 at 01:49 AM 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.
merlin3000 Posted December 28, 2006 at 11:41 PM Author Report #73122 Posted December 28, 2006 at 11:41 PM 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
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now