c++inheritanceprotected

Why can I not update the default values of a derived class through a constructor?


I am trying to wrap my head around inheritance.

I've created a BasePerson class that has some protected elements, and those elements have default values. I'm trying to "update" those default values in a derived class with other values, and call them from outside the class in the main.cpp file.

If I've understood inheritance properly, I should be able call the derived class from the main file and have the "updated" elements displayed, but I've made an error somewhere as only the default values from the base class are shown.

I've gotten the code to the point where, if I want, I can update the values from the main.cpp file, but this isn't what I'm trying to do.

#include <iostream>
#include <string>
#include "BasePerson.h"
using namespace std;

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

class BasePerson
{
protected :
    string st_firstName;
    string st_lastName;

public :
    double d_wagePerHour;

    BasePerson()
    {
        st_firstName = "Default First Name";
        st_lastName = "Default Last Name";
        d_wagePerHour = 40.12;
    }

    BasePerson(string param_firstName, string param_lastName, double param_wage)
    {
        st_firstName = param_firstName;
        st_lastName = param_lastName;
        d_wagePerHour = param_wage;
    }

    //Print-all Function
    void fn_printAllInfo()
    {
        cout << "First Name: " << st_firstName << "\n" << "Last Name: " << st_lastName << "\n" << "Wage Per Hour: " << d_wagePerHour << endl;
    }
};

class Employee : public BasePerson
{
private :
    string st_career;

public :
    Employee()
    {
       st_career = "Default Career";
    }

    Employee(string param_firstName, string param_lastName, double param_wage, string param_career) : BasePerson(param_firstName, param_lastName, param_wage)
    {
        st_firstName = "Bob";
        st_lastName = "Vila";
    }
};

/*
    Notes:

        - Anything private will be inaccessible from the derived class and outside
        - Anything protected will be accessible from the derived class and inaccessible from the outside
        - Public is public.
*/

int main()
{
    BasePerson person1;
    person1.fn_printAllInfo();

    Employee emp1;
    emp1.fn_printAllInfo();

    return 0;
}

Solution

  • First of all, I'd caution that I don't see many of what I consider good uses for inheritance.Although this does make some actual use of it, I think the case for it is still fairly weak.

    Good uses for inheritance nearly always involve the base class declaring at least one virtual function, and the derived class providing an implementation of that virtual function. I've added a (semi-)useful virtual function to demonstrate at least the general idea.

    Second, it seems to me that you're overloading constructors in a situation where it's probably simpler and more straightforward to just provide default parameter values instead.

    Third, when a ctor is going to initialize a value, it's generally better for it to do so in an initializer list rather than doing an assignment in the body of the ctor. Sometimes (e.g., initializing a reference) this is strictly required; most other times it's still preferable. I'd say at least 90% of the time that I write a ctor at all, its body is empty.

    Fourth, by default data should be private. If you think you have a good reason for protected data, write it down and think about it first. Then if you've thought it through, and you're 100% certain that the circumstances justify making it protected in this particular, highly unusual case, then you can go ahead and make it private.

    Fifth, to print an object of some class, I'd provide an overload of operator<< to do that.

    Sixth, formatting code for readability is quite important.

    class BasePerson
    {
    private:
        string st_firstName;
        string st_lastName;
        double d_wagePerHour;
    public:
        BasePerson(string param_firstName = "Default First Name", 
                          string param_lastName = "Default Last Name", 
                          double param_wage=40.12)
        : st_firstName(param_firstName),
          st_lastName(param_lastName),
          d_wagePerHour(param_wage)
        {
        }
    
        virtual std::ostream &print(std::ostream &os) const { 
            return os << "First Name: " << st_firstName << "\n" 
                      << "Last Name: " << st_lastName << "\n" 
                      << "Wage Per Hour: " << d_wagePerHour << "\n";
        }
        friend std::ostream &operator<<(std::ostream &os, BasePerson const &b) { 
            return b.print(os);
        }
    };
    
    class Employee : public BasePerson {
        string st_career;
    public:
        Employee(string const &firstName = "Bob",
                 string const &lastName = "Villa",
                 double wage = 40.12,
                 string career = "Default Career")
           : BasePerson(firstName, lastName, wage),
             st_career(career)
        {}
    
        virtual std::ostream &print(std::ostream &os) const override { 
            BasePerson::print(os);
            return os << "Career: " << st_career;
        }
    };
    
    int main()
    {
        BasePerson person1;
        std::cout << person1 << "\n";
    
        Employee emp1;
        std::cout << emp1 << "\n";
    
        return 0;
    }
    

    Live on Godbolt