Start learning free

LESSON 561 OF 572 · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

Employees and Managers in C#: Inheritance and override

Practice O(1) Read the full explanation

A company pays every employee a salary. A manager is an employee too, but earns a bonus on top of the salary. Write the two classes so that a manager reuses everything an employee has, and changes only how its pay is worked out.

Implement the class Employee:

  • Employee(name, salary) creates an employee. The name and the salary are private to Employee.
  • pay() returns the salary.
  • describe() returns the text <name> earns <pay>, where the amount is what pay() returns, for example Ana earns 3000.

and the class Manager, which inherits from Employee:

  • Manager(name, salary, bonus) lets the parent's constructor store the name and the salary, and stores the bonus itself, private to Manager.
  • pay() returns the parent's pay() plus the bonus. Call the parent's version, as in the lesson Calling the Parent Method: the salary is private to Employee, and the parent's pay() is what knows how an employee is paid.
  • describe() is not written again: Manager inherits it unchanged. Because describe() calls pay(), a manager's description shows the manager's pay, bonus included.

The input is a list of people, one per line: employee name salary or manager name salary bonus. For each line, the code that tests your classes creates that object and prints what its describe() returns, on a line of its own. The starter code spells these names the way your language does.

 

Example 1:

Input:
    employee Ana 3000
    manager Bob 4000 1000
Output:
    Ana earns 3000
    Bob earns 5000
Explanation:
Ana's pay is her salary. Bob's pay is the parent's pay, his salary 4000, plus his bonus 1000.
Bob's describe() is Employee's describe(), but the pay() it calls is Manager's.

Example 2:

Input:
    manager Cleo 5000 0
    employee Dan 5000
Output:
    Cleo earns 5000
    Dan earns 5000
Explanation: A manager whose bonus is 0 earns exactly the salary, like an employee.

Example 3:

Input:
    manager Eve 7000 2500
    employee Finn 2800
    employee Gus 3100
    manager Hana 6000 500
Output:
    Eve earns 9500
    Finn earns 2800
    Gus earns 3100
    Hana earns 6500
Explanation: Employees and managers come in any order, and each object keeps its own name and numbers.

 

Constraints:

  • 0 <= salary <= 106
  • 0 <= bonus <= 106
  • A name is one word of 1 to 20 English letters. Two people may have the same name.
  • At most 100 people per test case.
STEP 1 OF 8
    Ctrl + Enter to check

    C# · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

    Employees And Managers in C#, explained

    Problem overview

    A company pays every employee a salary. A manager is an employee too, but earns a bonus on top. The task is two classes: Employee stores a name and a salary, and Manager inherits from it and changes only how pay is worked out.

    • Employee(name, salary) keeps both values private. Pay() returns the salary, and Describe() returns text like Ana earns 3000.
    • Manager(name, salary, bonus) passes the name and the salary to the parent and stores the bonus itself. Its Pay() returns the parent's pay plus the bonus.
    • Describe() is not written again for managers.

    Ana, an employee with salary 3000, earns 3000. Bob, a manager with salary 4000 and bonus 1000, earns 5000.

    Approach

    Inheritance lets Manager reuse everything in Employee. A manager is an employee that has a bonus too, so Manager declares only what is new: the bonus field and a different Pay.

    The interesting part is Describe. It is written once, in Employee, and builds its text with a call to Pay(). When it runs on a manager, that call reaches the manager's version of Pay, so the bonus shows up without a second Describe. This works because Pay is declared virtual in the parent and override in the child: a call to a virtual method runs the version belonging to the object's real type.

    The salary is private to Employee, so Manager can't read it. That is why the manager's pay is written as the parent's Pay() plus the bonus: the salary stays with the code that owns it.

    Step by step

    1. Employee's fields: a private string name and a private int salary. Not even Manager can use them.
    2. Employee's constructor stores both parameters with this.name and this.salary.
    3. Pay returns salary. The keyword virtual in its header allows a subclass to replace it.
    4. Describe returns name, then " earns ", then Pay(), joined with +. Adding an int to a string with + turns the number into text. Calling Pay() rather than reading salary is what makes managers work.
    5. Manager: declare it as class Manager : Employee, with its own private int bonus.
    6. Manager's constructor has : base(name, salary) in its header, which runs Employee's constructor first. Its body stores this.bonus.
    7. Manager's Pay is marked override and returns base.Pay() + bonus.

    The solution in C#

    class Employee {
        private string name;
        private int salary;
        public Employee(string name, int salary) {
            this.name = name;
            this.salary = salary;
        }
        public virtual int Pay() {
            return salary;
        }
        public string Describe() {
            return name + " earns " + Pay();
        }
    }
    class Manager : Employee {
        private int bonus;
        public Manager(string name, int salary, int bonus) : base(name, salary) {
            this.bonus = bonus;
        }
        public override int Pay() {
            return base.Pay() + bonus;
        }
    }
    

    Using it:

    Employee[] all = {
        new Employee("Ana", 3000),
        new Manager("Bob", 4000, 1000),
        new Manager("Cleo", 5000, 0)
    };
    foreach (var e in all) {
        Console.WriteLine(e.Describe());
    }
    

    This prints:

    Ana earns 3000
    Bob earns 5000
    Cleo earns 5000
    

    The array holds all three people as Employee, yet Bob's line includes his bonus: the call to Pay() inside Describe picks the version for the real type.

    Details worth knowing

    • base has two jobs. In the constructor header, : base(name, salary) calls the parent's constructor. Inside a method, base.Pay() calls the parent's version of that method.
    • Overriding needs both keywords. The parent's method must be virtual (or abstract) and the child's must be override. Without virtual in the parent, the child's override does not compile.
    • Private is not inherited access. A Manager object contains a salary, but only Employee's code can read it.
    • Constructors run parent first. The parent's constructor fills the name and the salary, then the manager's body stores the bonus.

    Edge cases and common mistakes

    • Calling Pay() instead of base.Pay() in Manager.Pay. The method then calls itself forever. The program crashes with a stack overflow instead of returning a number.
    • Making the salary public to use it in Manager. This works but gives up the protection the lesson is about. Use the parent's Pay().
    • Writing Describe again in Manager. It is unnecessary: the inherited one already shows the manager's pay.
    • Bonus 0. A manager with bonus 0 earns exactly the salary: Cleo above earns 5000, as an employee with the same salary would.
    • Forgetting : base(name, salary). Employee has no constructor without parameters, so the manager's constructor wouldn't compile.

    Testing

    • employee Ana 3000 gives Ana earns 3000.
    • manager Bob 4000 1000 gives Bob earns 5000.
    • manager Cleo 5000 0 gives Cleo earns 5000.

    What the compiler tells you

    Two of the common slips are caught at compile time, with messages that name the problem:

    • If the parent's method isn't marked virtual, an override in the child fails with error CS0506: 'M.Pay()': cannot override inherited member 'E.Pay()' because it is not marked virtual, abstract, or override (with your own class names).
    • If the child's constructor doesn't pass the parent's arguments with : base(...), and the parent has no parameterless constructor, you get error CS7036: There is no argument given that corresponds to the required parameter 'n' of 'E.E(string, int)', again with your own names.

    The slip that is not caught at compile time is the recursion. Writing Pay() + bonus inside Manager.Pay is valid C#: it just calls the same method. Every call starts another call, none ever returns, and the program ends with a stack overflow.

    Why this design is useful

    Because Describe depends only on Pay(), adding another kind of employee later needs only a new Pay. A contractor class or a part-time class could override Pay and automatically get the right description. The text format lives in one place, and the pay rule of each kind lives in its own class.

    Key takeaways

    • A subclass declares only what is new and inherits the rest.
    • virtual plus override makes a call run the version for the object's real type.
    • base(...) and base.Method() reach the parent's constructor and methods.
    Keep going with C#500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free