Ir para o conteúdo
  • Revista PROGRAMAR: Já está disponível a edição #60 da revista programar. Faz já o download aqui!

arestides

Problemas no código - Final

Mensagens Recomendadas

arestides

Estas são as ultimas questões que coloco, espero que estas sejam úteis para vocês também.

1-

class Document
{
private:
	FILE *pdb;
public:
	Document (const char *filename) { pdb = fopen (filename, "t"); }
	Document (FILE *f = NULL) : pdb (f) {}
	~Document () {fclose (pdb); }
};

void assign(Document& d){
Document temp("letter.doc");
d=temp;
}

int main()
{
Document doc;
assign (doc);
return 0;
}

2-

String& String :: operator = (const String& s)
{
len = s.lan;
str = s.str;
index = s.index;
};

int main(){

String article ("the");
String common ("for example");

common = article;

return 0;
}

3-

class X {
public:
	X();
	X(int);
	X(const X&);
	X& operator=(const X&);
	// ...
};

class Y {
public:
	Y();
private:
	X x;
};

//...
Y::Y() { x=0; }
//...

4-

class Base{
public:
const Base &operator = (int);
//...
};

class derived: public base{
public:
Derived();
//...
};
int main(){
Derived d1;
d1 = 1;
//...
return 0;
}

5- Comentar a afirmação e dar um exemplo: "Na maioria dos casos a distinção entre as fases de inicialização e atribuição é transparente para o programador. Uma das excepções é o tratamento de membros const e referencias dentro de uma classe."

Mogers muito obrigado pela ajuda, tens de começar a dar explicações ao ppl k tens jeito :thumbsup:

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
arestides

ps: Em relação a questão 3 é para comentar a seguinte afirmação relacionada com o código: "A inicialização e atribuição são muitas vezes inadequadamente diferenciadas pelos programadores, facto k pode resultar numa ineficiente implementação de classes."

As restantes é para descobrir os problemas e eventuais soluções.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Triton

1- Na função assign estás a atribuir uma variável temporária (alocada na stack) ao d. Assim que sais da função, o valor do ponteiro deixa de existir.


<3 life

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
mogers

Nota prévia, tal como nos outros posts, espero não estar a dizer barbaridades. Corrijam-me sff se for esse o caso.

1) Este é bastante tricky e deu-me que pensar. Na minha opinião, o Triton está errado (ou interpretei mal o que ele quis dizer :D ). d é passado por referência e não é um apontador. Temos de analisar isto com calma:

(1) void assign(Document& d){
(2)         Document temp("letter.doc");
(3)         d=temp;
(4) }

(1): inicio da função. d é um Document cujo pdb = NULL devido ao 2º construtor.

(2): criação de um objecto temp cujo pdb está associado ao ficheiro "letter.doc"

(3): d torna-se uma cópia do objecto temp e o seu pdb também fica associado ao ficheiro "letter.doc"

(4): Aqui é que está o pormenor importante: o objecto temporário temp é destruído e no destrutor da classe Document há o fclose do apontador e este também afecta o apontador do objecto d!!! (ambos "apontam" para o mesmo endereço de memória)

Ou seja, a partir daqui o ficheiro não pode ser lido (doc.pdb é inútil). Podem confirmar com este simples programa:

#include <stdio.h>
class Document {
        private:
                FILE *pdb;
        public:
                Document (const char *filename) { pdb = fopen (filename, "r"); }
                Document (FILE *f = NULL) : pdb (f) {}
	void f() {
		char linha[1000];
		fscanf(pdb, "%s" , linha);
		printf("li: |%s|\n", linha);
	}
                ~Document () {fclose (pdb); }
};
void assign(Document& d){
        Document temp("letter.doc");
        d=temp;
}
int main() {
        Document doc;
        assign (doc);
// para ver a diferença, comentem as 2 linhas de cima e usem
// Document doc("letter.doc");
printf("executa f:\n");
doc.f();
        return 0;
}

2) Falta um return *this; no final do operador =, senão não há retorno do objecto. Penso que não há mais nenhum problema (o facto do operador retornar uma referência creio que não tem problema e len = s.lan não parece coerente, mas se calhar foi engano ao passar para aqui).

3) Estava a olhar para o sitio errado e se não fosse a pergunta se calhar não descobria. Neste caso pode ocorrer uma confusão entre o copy constructor e o operador =.

Definindo o copy constructor dessa forma (não se usou o explicit), este é chamado em casos como

X obj;
// bla bla bla
X outroObj = obj; // copy constructor é invocado pelo compilador

Neste caso, isto pode criar uma confusão ao programador pois este tem tanto o copy constructor como o operador = entre objectos da classe X definidos. Não sei bem o que é que queriam dizer com ineficientes neste caso, mas este é um dos exemplos. Se o operador = foi definido só para este tipo de utilização, então foi trabalho perdido para além de estar a fazer a mesma coisa em 2 sitios diferentes.

Assim, na minha opinião deveria-se optar por implementar apenas um destes 2.

4) Aqui é o problema do outro tópico, a classe derivada não herda o operador = da superclasse (definindo em Derived já funciona). Não tens acesso a nenhum livro com as propriedades da herança de classes? Eu já vi isso algures mas já não faço ideia onde.

5) Na maioria dos casos é indiferente usar a fase de inicialização ou de atribuição dos construtores para modificar os atributos da classe. Contudo, os atributos da classe que são constantes ou referências, têm de ser obrigatoriamente inicializados na fase de inicialização do construtor.

Mogers muito obrigado pela ajuda, tens de começar a dar explicações ao ppl k tens jeito :thumbsup:

lol. obrigado. eu só espero não te ter induzido em erro com as minhas respostas. Eu nunca dei explicações porque sempre achei que não tinha nem jeito nem paciência. Também não é agora prestes a terminar o curso que vou começar :)


"What we do for ourselves dies with us. What we do for others and the world, remains and is immortal.", Albert Pine

Blog pessoal : contém alguns puzzles, algoritmos e problemas para se resolver com programação.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
TheDark

Creio que a questão da ineficiência na 3 tem a ver com o caso onde tens um construtor a inicializar os campos, e um operator= a copiá-los entre dois objectos. Por exemplo:

class X {
    int x, y;

public:
    X(): x(0), y(0) { }

    X(int _x, int _y): x(_x), y(_y) { }

    X &operator=(const X &other) {
        this->x = other.x;
        this->y = other.y;
        return *this;
    }
};

int main() {
    X x1(10, 20), x2(x1), x3 = x2, x4;
    x4 = x3;

    return 0;
}

A construção dos 4 objectos do tipo X parece igual, mas não é, sobretudo a de x4. No fim, ficam todos com valores iguais, e de facto, é utilizado o mesmo construtor (o que recebe uma referência para X) para construir x2 e x3, mas x4 é criado com o construtor sem parâmetros, e aos seus campos são atribuídos valores por omissão, sendo em seguida alterados pelo operator=, o que origina 4 atribuições de valores em vez das 2 originadas pelos outros construtores.


Desaparecido.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Triton

1) Este é bastante tricky e deu-me que pensar. Na minha opinião, o Triton está errado (ou interpretei mal o que ele quis dizer :thumbsup: ). d é passado por referência e não é um apontador. Temos de analisar isto com calma:

Hmm, agora que penso melhor acho que tens razão. Devo ter feito confusão com o copy-constructor e reference assignment.


<3 life

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
mogers

belo exemplo TheDark :thumbsup:


"What we do for ourselves dies with us. What we do for others and the world, remains and is immortal.", Albert Pine

Blog pessoal : contém alguns puzzles, algoritmos e problemas para se resolver com programação.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!

Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.

Entrar Agora

×

Aviso Sobre Cookies

Ao usar este site você aceita os nossos Termos de Uso e Política de Privacidade. Este site usa cookies para disponibilizar funcionalidades personalizadas. Para mais informações visite esta página.