alexhong2001 said:
When design a class, should always make it "derivable" as a base class?
You might think you can never ever change a class once written. People who
think that tend to make too many things virtual.
If you write lots of tests at the same time as you code, you become free to
implement only the simplest design that passes the tests. But if you then
add more tests requesting more features, you can then add code that passes
the tests, and refactor that code into a new, clean design.
Following this technique keeps you out of the debugger, and prevents you
from over-designing classes. You will make classes that contain behavior -
not specifically classes designed to be base classes. But when the time
comes to merge interfaces into a base class, after the change you can test
to ensure changing didn't add a bug.
Read /Design Patterns/ to see popular ways to put objects together into
object models.
Is
there really a situation that the designed class not "derivable"?
std::string is not derivable - it has no virtual methods, so there's no
reason to inherit it. Sometimes people inherit it to form a "convenience
class" that changes its interface a little.
But if we controlled the source to a class we would make it derivable when
we find a reason to.
When should make a member "protected"? Only when allowing the derived
class(es) directly access it?
I never saw a reason for "protected" but there might be one out there.
Disregard it.
Should destructor always be virtual?
Yes. This is a different topic - a Sane Subset. That means you don't write
every possible combination of C++ statements, you only use specific
combinations known to work, and you prefer them to all others. (Read
/Effective C++/ and /Exceptional C++/ to learn what a thin line C++ can
place between bad design and sanity!)
Always use references without a reason to use pointers. Always use local
storage without a reason to use heap storage, etc.
C++ permits bugs in certain situations with non-virtual destructors because
they also optimize certain other situations. So, treat a non-virtual
destructor as the exceptional case, when you need speed, and use virtual
destructors in all other situations.