Jump to content
  • Revista PROGRAMAR: Já está disponível a edição #60 da revista programar. Faz já o download aqui!

arestides

Problemas no código - Final

Recommended Posts

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:

Share this post


Link to post
Share on other 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.

Share this post


Link to post
Share on other 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

Share this post


Link to post
Share on other 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.

Share this post


Link to post
Share on other 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.

Share this post


Link to post
Share on other 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

Share this post


Link to post
Share on other 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.

Share this post


Link to post
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

×

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.