other than meaningful variable/function/class names? I seem to lose marks on design in school even though my program provides all the required functionality
How do I make my classes reusable and generic?
There are many books written on the subject. I have a library of dozens of books that I refer to regularly. There is no way anyone can sum up in this forum all the things that constitute good programming practices. There are things from the idiomatic (C++ specific programming tips) to larger issues of software design to things like what tools and processes are in place.
Use a source control system.
Practice test-driven development (TDD).
Read lots of books.
If making classes reusable and generic is your primary concern, you cannot beat TDD. Your unit tests are a second user of your classes and components. Classes that are written to be testable are much more reusable than those that are not written using TDD.
I have some advice, at least on creating reusable code.
When you determine that for your program you need to create a Foo class, ask yourself
the question "What would someone who needed a Foo object want to do with it?"
Most programmers ask the question "What do I need to do with a Foo object?"
As a result, they end up creating non-reusable functions that suit their one specific
need and cannot be used anywhere else.
For example, a programmer needs to write a program that implements a simple library.
The library is to be implemented with a linked list. The program needs to allow the user
to enter a new book title, ISBN, and author. The program must allow the user to look
up books by ISBN in one case and author in another and display the matching record(s).
So programmer goes off and writes class Library and class BookNode, and then Library
has the following methods:
1) Add(): asks the user to enter a title, ISBN, and author, then inserts new record.
2) LookupByISBN(): asks the user to enter an ISBN, then looks up the book with that ISBN and displays it.
3) LookupByAuthor(): asks the user to enter an author, then looks up all books by that author and displays them.
Is BookNode reusable? Probably not. Is Library reusable in any other program you'll ever write? No. Are any of the methods reusable in other programs without modification? No. When programmer next has to go implement a gradebook program which is to also use a linked list, would s/he be able to reuse any of the linked list manipulation code? Not really. At least not without changing the name of struct BookNode to struct StudentNode and stripping out most of the code from Add. And the Lookup methods are even harder to pull code out of. At which point it wasn't really reused at all. Which leads me to another point I want to make: copy-paste is not reuse; it is duplication. The difference? A bug in the code has to be fixed once in the reuse case and N times in the duplication case. Said another way, copy-paste is less maintainable than reused code.
So what is reusable here? Nothing. The problem was that the programmer thought only of his/her immediate needs. It is impossible to write generic code if you only think of one use case.
But what could be reusable? Well, the program required you to write a linked list. A linked list, generically speaking, is a data structure in which there exists a head pointer which refers to the first node in the list. Each node then contains 1) the data to store, and 2) a pointer to the next node in the list. Linked lists are used by lots of programs. Maybe that should be reusable. So what operations would a programmer who needed a linked list use? To answer this, you have to think generically. You can't think "well, if I had a linked list of book nodes, I'd want to look up a book by ISBN". You don't have a linked list of book nodes; you have a linked list of stuff.
So I leave the challenge to you to think of what operations would a programmer expect to have on a linked list.