UPI Study › Courses › C++ Programming › Free lessons › Lesson 11.7 Free with a free account
Capstone: Inheritance, Polymorphism and Memory
C++ Programming · Chapter 11: Inheritance and PolymorphismSection 11.7 · lesson 84 of 84video coming soon
In this lesson
Applied challenge: a payroll register.
- An abstract base with derived types that answer differently
- One container of base handles, dispatching at run time
- Memory owned clearly and released on every exit path
- Records saved, reloaded as the right kind, behind a robust menu
Transcript
Everything said in the video, section by section (1,658 words). Read along, or search it.
Opening Question
One Loop, Three Answers, No Leaks
Nothing new appears in this section. This is one project that needs almost everything built so far to work at the same time. A hierarchy with genuine dispatch, memory obtained and correctly returned, records that survive the program ending, and an interface a person can actually use. The individual pieces are familiar. Making them cooperate is the exercise. So here's the question to carry through it: what has to be true for one loop to give three employees three different answers, and leak nothing?
Prior Material
Every Requirement Reuses Earlier Topics
Every requirement is something you've already covered. The type hierarchy draws on members, access sections, and inheritance modes. Different answers to one request need the marking that makes a call consult the object, rather than the handle. A mixed container needs vectors and pointers. Memory that's returned needs ownership and the destructor. Data that outlives the run needs files and fixed-length records. A usable interface needs the menu loop and input checking. And a markable submission needs the specification, planned tests, and milestones. The synthesis is the new part.
Project Brief
Building an Abstract Payroll Register
The brief: build a payroll register. It holds a workforce of mixed kinds, and computes what each person is owed for the month. It saves to a file, reloads on the next run, and is driven from a menu. The base, employee, is abstract. It holds the id and name, and declares two requests: describe yourself, and what are you owed. Salaried and hourly employees are required. Commissioned is a stretch goal. Each kind answers the same two requests differently.
Pay Rules
Figures Your Test Runs Must Reproduce
Here are the pay rules, with the figures your test runs must reproduce. Salaried pay is the annual salary divided by twelve. Nine hundred sixty thousand rupees a year gives eighty thousand. Hourly pay is rate times hours, with hours above one hundred sixty paid at one and a half times. At two hundred fifty rupees an hour for one hundred seventy hours, that's forty-three thousand seven hundred fifty. For one hundred twenty hours, thirty thousand. Commissioned pay is a retainer plus a percentage of sales. Twenty thousand, plus eight percent of five hundred thousand, gives sixty thousand.
Requirement A
Abstract Base With Marked Requests
Requirement A is the hierarchy. The base must be abstract. At least one request is declared without an answer, so no base object can be created. Both requests are marked so that a call through a base handle reaches the actual object's version. The base destructor is marked the same way. Without it, releasing a derived object through a base handle skips the derived clean-up. Shared data, the identifier and name, belongs in the base. Data specific to one kind belongs in that kind. And every replacement in a derived type carries override, so the compiler checks the signature.
Requirement B
Dispatch Across a Mixed Container
Requirement B is the whole point of the exercise, in a few lines. A vector of employee pointers holds a salaried employee, Anita, and hourly ones, Ravi and Meera, plus Dev on commission. One loop asks each to describe itself, and prints its pay. One loop, one call, and different behavior per element. Every figure matches the pay table. If your output prints the same description for every entry, the marking on the base declarations is missing. That single symptom is the difference between this project working, and merely compiling.
Requirement C
Memory Released Once on Every Path
Requirement C is memory, and here are the rules it's marked against. Every block obtained is released exactly once. The container's blocks were obtained one at a time, and nothing releases them automatically. The base destructor is marked for dispatch, because elements are released through base handles. Check it with derived destructors that print. Pointers are set to nothing after release, during shutdown, and when an entry is deleted. A later read must fail visibly, not quietly. And release happens on every exit path, because the menu has several ways to end, including an error path.
Demo
Releasing Elements Through Base Handles
Here is that check running. After the listing, release every element through its base handle. Each derived destructor announces itself, so a line appears for every object. Then the register is cleared, and the pointers are set to nothing.
Common Mistake
The Silent Leak From Unmarked Destructors
One of those rules catches most people. Releasing a derived object through a base handle runs only the base clean-up, unless the base destructor is marked for dispatch. Nothing warns you. The program runs, the output is right, and the leak is silent, and per object. Strictly, it's undefined behavior, so we never run it. The compiler can warn, though, and here is its real warning for the unmarked destructor. So prove yours works. Print a line from each derived destructor, and check that those lines appear when the container is emptied.
Requirement D
Fixed-Shape Tagged Records in Files
Requirement D is persistence, and it's the design problem this project is really built around. A file holds bytes. It doesn't hold types. Writing three kinds of object into one file, and reading them back, means recording in the file which kind each record was. So every record has the same fixed shape: a tag, an id, a name, and two values, whose meaning depends on the tag. One record: the same size whatever the kind. For a salaried record, value A is the annual salary. For hourly, it's the rate and the hours. For commissioned, the retainer and the month's sales.
Save and Load
Writing Records and Rebuilding Objects
Saving walks the container, asks each element for the values that describe it, fills one tagged record, and writes it. The record must be a plain, fixed-size type. Objects are never written directly. Loading reads one record at a time, looks at the tag, builds an object of the matching kind, and adds its handle to the container. An unrecognized tag is reported and skipped, never assumed. And a part-read record ends the load. Run it: the register is released, then reloaded from the file, and every kind comes back as itself, with the same pay.
Design Rationale
Why Objects Are Not Written Directly
Why not just write the object out? It carries the machinery that makes dispatch work. Read back on another run, it isn't a valid object at all. So convert to a plain record on the way out, and construct a real object on the way in. That conversion is the persistence layer.
Requirement E
Eight Menu Options and Their Pitfalls
Requirement E is the interface, with eight required options. Add an employee, list everyone with pay, find or remove by identifier, show the payroll total, save, load, and quit. Option seven is the one worth planning. Loading over an existing register must release what's already held first, or every load leaks the previous contents. Option four must release the block before removing the handle. Remove first, and the address is gone. And quit releases everything before ending.
Requirement F
One Type Per Pair of Files
Requirement F is file organization, with one type per pair of files. The employee files hold the abstract base, included by everything else. The salaried and hourly files each hold one derived kind, and include the base header. The register files hold the container, its operations, and saving and loading. That's where the memory rules live. And main holds only the menu loop and input handling. No pay rules, and no file work.
Milestones
Seven Runnable Steps Over Fifteen Hours
Here are the suggested milestones, each ending in something that runs. Allow roughly fifteen hours, across several sittings. Start with the specification and design sketches. Then the base and one derived kind, with one object describing itself. Then the second kind and the dispatch loop, where two kinds print two different descriptions. Then memory correctness, then saving and loading, where save, quit, restart and load brings back the right kinds. Then the menu and input handling, then the split across files. And finally, testing and the write-up.
Submission
What to Hand In With Evidence
Here's what to submit. The specification's four lists, and design sketches dated before the code. The source, building cleanly with warnings enabled, along with the exact build command. Testing evidence: every figure in the pay table, a save, quit, restart and load transcript, and invalid inputs refused. Memory evidence: your own block count at shutdown, plus leak-checked runs for at least two exit paths. A design write-up of six hundred to nine hundred words. And a milestone log with part-built versions, assembled as you go, not reconstructed at the end.
Marking Rubric
Seven Dimensions That Must All Pass
The rubric has seven dimensions, and a passing submission must be sound on every row. Hierarchy design: an abstract base, data where it belongs, and every replacement checked by the compiler. Dispatch: one loop over base handles with genuinely different behavior. Memory: clean leak checks, with derived clean-up demonstrably running. Persistence: mixed kinds reload as the correct kinds. Interface robustness: bad input refused, without ending the program. Organization: the required file split. And evidence: expected values computed by hand, and a write-up that explains decisions rather than describing code.
Final Checklist
Checks to Run Before Submitting
Before you submit, check each of these. Creating a base object directly is rejected by the compiler. If it isn't, the base isn't abstract. Here is that check, with a base object added to main. The listing loop prints different descriptions for different kinds. Each derived destructor announces itself when the register is emptied, and leak checks report nothing lost. A saved file reloads every kind correctly, even after the program has closed. And loading twice in a row doesn't increase the memory held. Finally, every figure in the pay table is reproduced exactly.
Quick Check
Same Description for Every Employee
Quick check. A classmate's listing prints the same description for every employee, yet it builds without a single error. Which two rules from Requirement A did that code break? Pause and think. First, describe isn't marked virtual in the base, so the call is decided by the handle's type, not the object's. Second, the derived versions don't carry override. With it, the compiler would have refused the build, and pointed straight at the mistake.
Key Takeaways
Marked Base, Owned Blocks, Tagged Records
To close. Build an abstract base with marked requests and a marked destructor, and write override everywhere. Hold everything in one container of base handles, and let one loop ask each element to answer as itself. Own every block, and release it once, on every path. And write tagged plain records out, constructing real objects back in.
About C++ Programming at UPI Study
C++ Programming (Computer Science 242) is a self-paced online course of 84 video lessons in 11 chapters, from your first program to decisions, loops, arrays, functions, classes, files, pointers and inheritance. It carries a NCCRS credit recommendation for 3 semester credits.
Every lesson transcript is free on pages like this one, and the videos are free with a free UPI Study account. Enrolling adds a practice quiz after each lesson, the graded work and final exam that earn the credit, lifetime access, and an official transcript on completion. UPI Study has helped over 130,000 students with college credits. ACE and NCCRS have over 2,100 cooperating colleges that will consider accepting credits; the final decision is with the universities.
Enroll now → Course details Download the syllabus Every course with PRO →
Why take it here
Why students take C++ Programming with UPI Study
Where the credit goes
Universities that work with NCCRS
C++ Programming carries a NCCRS credit recommendation. These universities work with NCCRS; some are UPI Study's signed partners. ACE and NCCRS have over 2,100 cooperating colleges that will consider accepting credits; the final decision is with the universities.
Thomas Edison State UniversitySigned partner
University of the PeopleSigned partner
Charter Oak State CollegeSigned partner
Strayer UniversitySigned partner
Columbia Southern UniversitySigned partner
Indiana TechSigned partner
Penn StateWorks with NCCRS
Southern New Hampshire UniversityWorks with NCCRS
SUNYWorks with NCCRS
+many more cooperating universitiesFind my college →Find my college → Not listed? Ask Athena in the corner of this page, or book a 15-minute call.
FAQ
Questions students ask us
About Capstone: Inheritance, Polymorphism and Memory
Why does my C++ loop over base-class pointers print the same description for every derived object?
Why does a base class destructor need to be virtual when deleting derived objects through base pointers?
How do you save and reload objects of different derived classes from one binary file in C++?
What memory mistakes should I avoid when a C++ menu program manages a vector of base-class pointers?
About the C++ Programming course
How many college credits is C++ Programming?
How much does C++ Programming cost and what is included?
Which universities accept UPI Study credits?
How long does C++ Programming take?
How are the exams done?
How do my credits reach my college?
Ready for the full course? Earn 3 credits in C++ Programming.
84 video lessons, a quiz after each one, and the graded work that earns the credit. Recommended for credit by NCCRS.
3 credits · NCCRSEnroll →