Assign one class to another in C ++

1

There is a class like below:

class vetor
{
protected:
    int x, y;
public:
    //Construtor
    vetor(int _x=0, int _y=0);
};

and another:

class pos : public vetor
{

public:
    //Construtor
    pos();

    umaFuncaoQualquer(int _x=0, int _y=0);
    outraFuncaoQualquer(int _x=0, int _y=0, bool algo=false);
    maisUmaFuncaoQualquer(void);
};

I want to do this:

vetor v(1, 3);
pos p;
p = v;

How would you do this in C ++? Need to create a function for this, or am I thinking the wrong way?

  

Up 1:

I was able to do this in the vector class:

class vetor
{
protected:
    int x, y;
public:
    //Construtor
    vetor(int _x=0, int _y=0);

    //Retorna x
    int getX(void);
    //Retorna y
    int getY(void);
};

in class pos:

class pos : public vetor
{

public:
    //Construtor default
    pos();
    /*
    Construtor para receber o vetor. É responsável por atribuir a x e y 
    herdados pela classe vetor o x e y de uma instância vetor atribuída, 
    utilizando as funções getX e getY da classe vetor, 
    que pega o x,y que estão protected na mesma.
    Sua implementação:
    pos::pos(vetor _v)
    {
        x = _v.getX();
        y = _v.getY();
    };
    */
    pos(vetor _v);

    umaFuncaoQualquer(int _x=0, int _y=0);
    outraFuncaoQualquer(int _x=0, int _y=0, bool algo=false);
    maisUmaFuncaoQualquer(void);

};

so the code below works:

vetor v(1, 3);
pos p;
p = v;

However, I would like to know other ways to do the same, maybe there are ways that will fit better in this situation. And I did not understand very well because this way works and the first does not, if both have x and y. I remember reading about it sometime:

//Funciona sem precisar do construtor de cópia
v = p;
//Apenas funciona se tiver um construtor de cópia
p = v;

I read that it is so, but I can not remember why?

  

Up 2:

Regarding the answer from @Ossetian_Odin, I still do not understand some points, I'll start from the top p bass:

1 - Regarding the use of friend, it would not be necessary in the case of my example, since the members of the "vector" class are protected and not private, so they can already be accessed by the derived class. And the copy constructor that the compiler declares is in the class itself receiving the class itself, how do I assign a different one, requires that I create a constructor for this, the problem is that I created in the class "pos" and not in the "vector" , which is somewhat confusing, but could not be the opposite, since following the logic "is a", "vector" is not a "pos", but "pos" is a "vector". Am I right?

2 - As for downcasting, you say to create an abstract class, so would I create the "vector" class as abstract? Would not it be better to use dynamic_cast in this case? And if I use "dynamic_cast" what happens when I do "dynamic_cast (& v);", p will have all the variables and functions of "pos" (since it inherits "vector", are the of "vector" and those that only exist in "pos"), receiving the assignment of v the variables that have in common, or p have only what "vector" has?

  

Up 3:

I gave it one study, and I realized that the way I did in Up 2 is the right one for this case, at least the most certain I've found so far. For what I want to do is assign a "vector" object to an "pos" object in the most "abstract" possible way, abstraction for another person to use, it is easier to do "p = v;" than "static_cast (& vet);" for example; what I need is not a downcasting, nor to use polymorphism, but I am grateful for both answers that made me study these concepts more, because what is really needed in this case is simply to assign "p = v", where p a constructor to handle the assigned class will work, not conversion (polymorphism) it needs, but a copy. I gave a read in a material that I found in google, and in the chapter "Conversion of pointers" clarified me:

link

Translating to the question variables:

 vetor v, *pv; // pv pode apontar para objetos do tipo vetor e derivados
 pos p, *pp; // pp pode apontar para objetos do tipo pos e derivados

 v = p; // copia v parte vetor de p para v (não é conversão)
 p = v; /* erro! v pode não ter todos elementos para a cópia(A questão se 
           refere a este caso, que também não é conversão, e pode ser 
           resolvido da maneira do Up 2, o que queria saber era se existe
           outras maneiras alem da que fiz no Up 2, que seria para cópia, 
           e não mudança de forma ou tratar um classe como uma 
           diferente)
        */

 pv = &v; // ok
 pv = &p; // ok, pv aponta para um objeto do tipo pos
 pp = pv; // erro! pv pode apontar para um objeto do tipo vetor
 pp = &p; // ok
 pp = &v; // erro! pp não pode apontar para objetos do tipo vetor 
    
asked by anonymous 03.07.2017 / 07:06

2 answers

1

You are trying to treat an object of the parent class as an object of the child class. This does not work.

Concrete example

Imagine that you have the animal , gato (inheriting from animals) and urocordato classes. A animal has the comer method. A gato also has the miau , serFofo and ignorarDono methods. A urocordato also has methods metamorfose , filtrar and brotamento .

Imagine that for your algorithm you need a animal , let's call that estimacao animal:

animal estimacao;
estimacao = new gato();
// faz trabalho com um animal do tipo gato
estimacao = new urocordato();
// faz trabalho com animal do tipo urocordato

There is no problem with the above algorithm. Now imagine that we have a function that gets a gato as an argument. Let's call this function mimar , its signature is void mimar(gato xano); . See what happens below:

//declaração e objeto do tipo gato, tudo certo
gato xaninho = new gato();
mimar(xaninho);

// declaração de animal, objeto gato; possível atribuir, mas não possível chamar 'mimar'
animal bixo = new gato();
mimar(bixo);

// declaração de gato, objeto urocordato; impossível atribuir
gato xaninho = new urocordato();
mimar(xaninho);

Why this?

When you work with inheritance, you can assume that urocordato and gato can be treated as animals. Class definition speaks just this through inheritance:

  • class gato is derived from class animal : means gato is a specific type of animal
  • class urocordato is derived from class animal : means urocordato is a specific type of animal

However, you can not treat a% generic% as a animal . When you do gato you are trying to treat a gato xaninho = new urocordato(); any as a animal .

If you could treat a gato any as a animal , you could call the gato method of a miau() (for example, in the urocordato implementation), void mimar(gato xano) s is not are able to do urocordato .

  

UPDATE

Automatic construction

If at some point you declare a class constructor with only a single argument object, you can assign the argument to the variable of that class. Internally, C ++ will automatically create a target class object by calling the appropriate constructor. This has nothing to do with inheritance.

Example without using relation between miau() and gato :

int giid = 0;

class animal {
public:
    int id;
    int iid;
    animal(int _id = 0) {
        cout << "construindo um animal..." << endl;
        id = _id;
        iid = giid++;
    }

};

class gato {
public:
    int id, iid;
    gato(animal a) {
        id = a.id;
        iid = giid++;
        cout << "construtor chamado automaticamente, meaw" << endl;
    }
};

//códigos...
animal a;
gato xano = a; // chama o construtor de gato passando um animal

cout << "instance id do animal " << a.iid << endl;
cout << "instance id do xano " << xano.iid << endl;
//códigos...

See working at ideone .

Exit execution:

  

building an animal ...
  constructor called automatically, meaw
  instance id of animal 0
  instance id of xano 1

I also put together another example that, this yes, made the confusion:

int giid = 0;

class animal {
public:
int id;
int iid;
animal(int _id = 0) {
cout << "construindo um animal..." << endl;
id = _id;
iid = giid++;
}

};

class gato: public animal {
public:
gato(animal a) {
id = a.id;
cout << "construtor chamado automaticamente, meaw" << endl;
}
};

// códigos...
animal a;
gato xano = a;

cout << "instance id do animal " << a.iid << endl;
cout << "instance id do xano " << xano.iid << endl;
// códigos...

See working at ideone

Exit execution:

  

building an animal ...
  building an animal ...
  constructor called automatically, meaw
  instance id of animal 0
  instance id of xano 1

    
03.07.2017 / 13:45
1

I did not understand the purpose / logic of your code. I think what you want to do is called "downcasting", which is only possible through pointers and references:

#include <iostream>
using namespace std;


class vetor
{
protected:
    int m_x;
    int m_y;

public:
    vetor(int x = 0, int y = 0)
    {
        m_x = x;
        m_y = y;
    }

    void imprime()
    {
        cout << "imprimindo como \'vetor\'";
        cout << "\nx: " << m_x;
        cout << "\ny: " << m_y << "\n\n";
     }
};


class pos : public vetor
{
public:
    pos(int x, int y) : vetor(x, y) {} //chama o construtor da classe base

    void imprime()
    {
        cout << "imprimindo como \'pos\'";
        cout << "\nx: " << m_x;
        cout << "\ny: " << m_y << "\n\n";
    }
};


int main()
{
    vetor vet(10, 20);
    vet.imprime();

    pos* ps = static_cast<pos*>(&vet);
    ps->imprime();

    return 0;
}

However, using a pointer / reference from a derived class to a base object is not a good programming practice, because it will only work if the base and derived class layout are the same as leaving your program with a logic confusing, breaking the class hierarchy. And it also would not work if you were using virtual functions.

The right thing is for you to create an abstract base class and use it to refer to derivative objects, using the "is one" logic, which @Jefferson Quesado explained:

#include <iostream>
#include <memory>
using namespace std;


class Poligono //classe abstrata
{
public:
    virtual void desenha() = 0; //função virtual pura
    virtual ~Poligono() {} //destrutor é declarado virtual para que seja chamado quando objeto 
     //filho for destruído
};


class Triangulo : public Poligono
{
public:
    void desenha() override //implementa função virtual
    {
        cout << "Desenha triangulo.\n";
    }
};


class Retangulo : public Poligono
{
public:
    void desenha() override
    {
        cout << "Desenha retangulo.\n";
    }
};


void FacaAlgumaCoisa(Poligono& pol)
{
    pol.desenha();
}


int main()
{
    unique_ptr<Poligono> pol; //ponteiro da classe base abstrata

    pol = make_unique<Triangulo>(); //usa pol como triângulo
    pol->desenha();

    pol = make_unique<Retangulo>(); //destroi triângulo e usa pol como retângulo
    pol->desenha();

    //usa uma função para obter o mesmo efeito acima
    FacaAlgumaCoisa(Retangulo());
    FacaAlgumaCoisa(Triangulo());

    return 0;
}

About the copy constructor, it is the constructor that you define to determine the behavior of your class when it is assigned:

class Pessoa
{
    string nome;
    int idade;

public:
    //construtor pra inicializar
    Pessoa(const string& nome, int idade)
    {
        this->nome = nome;
        this->idade = idade;
    }

    //construtor de cópia
    Pessoa(const Pessoa& p)
    {
        cout << p.nome << " esta sendo copiado(a)!\n";
        nome = p.nome; //se os objetos fore do mesmo tipo, vc pode acessar os membro privados
        idade = p.idade;
    }
};

Using the class:

Pessoa p1("John", 30);
Pessoa p2 = p1; //chama o construtor de cópia
Pessoa p3(p1); //faz a mesma coisa que a linha acima

You can also use the copy constructor of a class to receive another type of object (just like you did, so your code worked when you assigned two classes of different types), but unless I'm wrong, you'll need to dial the class as "friend" of the other object with the keyword friend , if the two classes have no relation. And another detail is that if you do not declare the copy constructor, the compiler will declare one for the same type implicitly, and its default behavior is to call the assignment operator on all members of your class.

EDIT:

Responding to other questions:

1 - In case of your code, you do not need to declare as friend because the derived class has access to the protected fields of the base class. And no, the compiler generates the copy constructor implicitly in all classes so you do not declare it and implement it. When you call the copy constructor, obviously the default constructor of the base class is also called. I recommend that you create a base class and a derivative and run tests marking all constructors with std::cout to better understand the operation:

struct Base
{
    Base()
    {
        cout << "base created!\n";
    }

    Base(const Base& b)
    {
        cout << "copy constructor base\n";
    }
};

struct Child : Base
{
    Child()
    {
        cout << "child created!\n";
    }

    Child(const Child& c)
    {
        cout << "copy constructor child\n";
    }
};

2 - "Downcasting" is when you try to use a derived class as if it were a base class, which is the opposite of the second example I showed. The base class should be used as a pointer / reference, since the derivatives inherit all the characteristics of the base, and the opposite does not occur. And yes, "vector" should be abstract, but in that case it works because it is identical to the "pos" class. And dynamic_cast serves the same purpose as a static_cast normal, the difference is that this cast checks at runtime if the conversion is valid and returns a null pointer if it is invalid, and only works with classes with methods marked as virtual . In the first example of my post, if you tried to mark the "print" method as virtual, and replace static_cast with dynamic_cast , the conversion would fail for reasons I've already mentioned (and also because virtual functions work differently than common methods). Search for class hierarchy and polymorphism to better understand these concepts.

    
03.07.2017 / 19:18