0

Estoy tratando de aplicar POO a C++ y no consigo lograrlo, intento crear el objeto humano1 y mi codigo arroja errores, está bien estructurado el constructor? o solo debería colocar el constructor vacio? en mi caso, no necesitaría que se le asignen valores iniciales, se los asignaré yo. Al parecer el error está ligado al constructor que está fuera de la clase:

||=== Build: Debug in C++ POO (compiler: GNU GCC Compiler) ===|
D:\C++\Proyectos\C++ POO\main.cpp||In constructor 'Humano::Humano(int, std::string, std::string)':|
D:\C++\Proyectos\C++ POO\main.cpp|45|warning: unused variable 'edad' [-Wunused-variable]|
D:\C++\Proyectos\C++ POO\main.cpp||In function 'int main()':|
D:\C++\Proyectos\C++ POO\main.cpp|52|error: no matching function for call to 'Humano::Humano()'|
D:\C++\Proyectos\C++ POO\main.cpp|52|note: candidates are:|
D:\C++\Proyectos\C++ POO\main.cpp|44|note: Humano::Humano(int, std::string, std::string)|
D:\C++\Proyectos\C++ POO\main.cpp|44|note:   candidate expects 3 arguments, 0 provided|
D:\C++\Proyectos\C++ POO\main.cpp|5|note: Humano::Humano(const Humano&)|
D:\C++\Proyectos\C++ POO\main.cpp|5|note:   candidate expects 1 argument, 0 provided|
D:\C++\Proyectos\C++ POO\main.cpp|53|error: 'humano1' was not declared in this scope|
||=== Build failed: 2 error(s), 1 warning(s) (0 minute(s), 0 second(s)) ===|

Mi codigo:

#include <iostream>
#include <stdlib.h>
using namespace std;

class Humano {

    private:
        int edad;
        string sexo;
        string nombre;
    public:

        Humano(int _edad, string _sexo, string _nombre);
        void setEdad(int _edad) {
            edad = _edad;

        }

        void setSexo(string _sexo) {
            sexo = _sexo;

        }

        void setNombre(string _nombre) {
            sexo = _nombre;

        }

        int getEdad() {
            return edad;

        }

        string getSexo() {
            return sexo;

        }
        string getNombre() {
            return nombre;

        }
};

Humano::Humano(int _edad, string _sexo, string _nombre) {
    int edad = _edad;
    string sexo= _sexo;
    string nombre= _nombre;
}

int main(){

    Humano humano1;
    humano1.setEdad(18);
    humano1.setSexo("Hombre");
    humano1.setNombre("Pedro");
    cout<<humano1.getEdad()<<endl;
}

¿El uso de THIS, podría reemplazar el usar el nombre de los parametros como _edad,_sexo?

Raravar
  • 23
  • 3

2 Answers2

2

Como te han dicho en los comentarios, tu constructor necesita tres argumentos:

Humano::Humano(int _edad, string _sexo, string _nombre){...}

Y cuando quieres crear un objeto del tipo humano no le das ninguno:

Humano humano1;

¿Soluciones?

1.- La más obvia, crear el objeto humano con los argumentos que necesita:

Humano humano1(18,"Hombre","Pedro");

2.- Añadir un constructor que no necesite argumentos (en el ejemplo, inicializando valores, aunque no es necesario pero sí conveniente):

Humano::Humano(){
edad = 0;
sexo = "";
nombre = "";
}

3.- Añadiendo valores por defecto al constructor existente:

Humano(int _edad=0, string _sexo="", string _nombre="");

Te quedaría así (ambos constructores son lo mismo, puedes descomentar uno u otro):

#include <iostream>
#include <stdlib.h>
using namespace std;

class Humano {

    private:
        int edad;
        string sexo;
        string nombre;
    public:

        //Humano();
        Humano(int _edad=0, string _sexo="", string _nombre="");
        void setEdad(int _edad) {
            edad = _edad;

        }

        void setSexo(string _sexo) {
            sexo = _sexo;

        }

        void setNombre(string _nombre) {
            sexo = _nombre;

        }

        int getEdad() {
            return edad;

        }

        string getSexo() {
            return sexo;

        }
        string getNombre() {
            return nombre;

        }
};

/*Humano::Humano() {
    int edad = 0;
    string sexo= "";
    string nombre= "";
}*/

Humano::Humano(int _edad, string _sexo, string _nombre) {
    int edad = _edad;
    string sexo= _sexo;
    string nombre= _nombre;
}

int main(){

    Humano humano1;
    humano1.setEdad(18);
    humano1.setSexo("Hombre");
    humano1.setNombre("Pedro");
    cout<<humano1.getEdad()<<endl;
}

Sobre el uso de this, es un operador que apunta a la clase. De esta forma podemos acceder de forma segura (en el sentido de que accedemos a ellos y no a otros) a los miembros de la clase.

user3733164
  • 942
  • 1
  • 5
  • 12
  • 1
    Estimado, agradezco mucho su respuesta tan detallada. Obedeciendo a las buenas prácticas, cuál de ambos constructores usted recomienda, el que dejó sin comentar o el comentado(con variable sexo en 0), el primero o el ultimo? . Gracias y saludos. – Raravar Mar 28 '21 at 20:37
  • Bueno, lo mejor creo que sería tener un constructor con valores por defecto. Saludos. – user3733164 Mar 28 '21 at 21:13
  • El constructor con valores por defecto es el que está específicamente arriba del main verdad?, tampoco me agrada la idea de dar valores iniciales(como el que está comentado) – Raravar Mar 28 '21 at 22:18
  • Ya es un poco ver las necesidades que tengas. De todas formas, tal como tienes el constructor, cada vez que crees una instancia, has de darle los tres parámetros que requiere el objeto. El constructor con estos valores por defecto te permite crear instancias sin argumentos, asignando unos iniciales. Otra opción es crear el constructor sin argumentos. Te permitirá crear la instancia sin asignar ningún valor. Todo depende de tus necesidades o preferencias. – user3733164 Mar 29 '21 at 06:12
  • La mejor práctica no es un constructor con valores por defecto si no estudiar si el objeto realmente tiene sentido con valores por defecto ¿Tiene sentido un `Humano` sin edad, sexo o nombre? – PaperBirdMaster Mar 29 '21 at 06:34
0

Problema

El compilador da varios avisos de los problemas que se encuentra con el constructor, éstos son claros y concisos, tal vez no los entiendes por estar en inglés, los traduzco:

In constructor 'Humano::Humano(int, std::string, std::string)':
In function 'int main()':
error: no matching function for call to 'Humano::Humano()'
note: candidates are:
Humano::Humano(int, std::string, std::string)
candidate expects 3 arguments, 0 provided
Humano::Humano(const Humano&)
candidate expects 1 argument, 0 provided
En el constructor 'Humano::Humano(int, std::string, std::string)':
En la función 'int main()':
error: no coincide ninguna función para llamar a 'Humano::Humano()'
nota: los candidatos son:
Humano::Humano(int, std::string, std::string)
el candidato espera 3 argumentos, se proveen 0
Humano::Humano(const Humano&)
el candidato espera 1 argumento, se proveen 0

El compilador te está diciendo que intentaste construir en main un Humano, cuyo constructor declarado es Humano::Humano(int, std::string, std::string) pero no encontró ningún constructor para Humano que coincida con el constructor sin argumentos (Humano::Humano()).

A continuación el compilador intenta ayudar indicando qué constructores sí ha encontrado, dice que ha encontrado Humano::Humano(int, std::string, std::string) pero no vale porque necesita tres argumentos y no se le provee ninguno y también dice haber encontrado el constructor de copia Humano::Humano(const Humano&) (generado automáticamente por el compilador) pero tampoco le vale porque necesita un argumento y no se le provee ninguno.

Solución

Para solucionar el problema puedes proveer un constructor por defecto, ya sea manualmente:

class Humano {

    private:
        int edad;
        string sexo;
        string nombre;
    public:

        // Constructor sin parámetros (por defecto)
        Humano() : edad{}, sexo{}, nombre{} {
        }

     ...

O dejando que el compilador haga el trabajo:

class Humano {

    private:
        int edad;
        string sexo;
        string nombre;
    public:

        // Constructor sin parámetros (por defecto) generado por el compilador
        Humano() = default;

     ...

Propuesta

En realidad no tiene sentido que un Humano no tenga edad, ni sexo, ni nombre por lo que no permitir construir una instancia de esa clase sin proveer los datos tiene todo el sentido del mundo; yo no proveería un constructor por defecto pero sí que haría cambios en el código:

  • Las funciones de lectura de datos deben ser constantes: cuando una función no modifica el estado interno del objeto, ésta debe ser constante. Esto permite que al compilador tomar decisiones de optimización y además denota la intencionalidad del autor:
        int getEdad() const {
        //            ^^^^^ <--- Función constante, no modifica el objeto
            return edad;
        }
        string getSexo() const {
        //               ^^^^^ <--- Función constante, no modifica el objeto
            return sexo;
        }
        string getNombre() const {
        //                 ^^^^^ <--- Función constante, no modifica el objeto
            return nombre;
        }
    
  • Copias innecesarias: Las funciones de lectura de datos pueden devolver una referencia constante, así no se copian los datos internos. El constructor y las funciones de escritura de datos también pueden recibir referencias constantes para evitar copias:
        Humano(int _edad, const string &_sexo, const string &_nombre) :
        //                ^^^^^^^^^^^^^^       ^^^^^^^^^^^^^^
        //                      referencias constantes
            edad{_edad},
            sexo{_sexo},
            nombre{_nombre}
        {}
        void setEdad(int _edad) {
            edad = _edad;
        }
        void setSexo(const string &_sexo) {
        //           ^^^^^^^^^^^^^^ <--- Referencia constante
            sexo = _sexo;
        }
        void setNombre(const string &_nombre) {
        //             ^^^^^^^^^^^^^^ <--- Referencia constante
            sexo = _nombre;
        }
    
  • Quita las cabeceras de : La cabecera <stdlib.h> pertenece a C y no debe ser usada en código C++, lee este hilo para saber más del tema.
  • No abuses de la cláusula using namespace std: Y menos aún en archivos de cabecera, lee este hilo para saber más del tema.
PaperBirdMaster
  • 44,474
  • 6
  • 44
  • 82
  • Muchas gracias por su respuesta, esto me servirá mucho para aprender y hacer uso de las buenas normas – Raravar Mar 30 '21 at 03:37