For me, if a class calls a duplicate function of another class (the stopwatch example you've given calls 'getElapsedTime' - which is a duplicate function of sf::Clock), I feel that's a signpost saying 'this class needs to be a subclass', especially if it shares variables and merely 'adds additional functions'.
If I pass my AdvancedClock (to you, a type of stopwatch) to a function, the function can still treat it as though a clock - because it still has those types of variables and functions in-place: getElapsedTime, restart etc.
If you have a `pause` function in your stopwatch (and don't play around with names; an advanced clock with stopwatch-esque capabilities is a stopwatch) you don't merely add a function, you change the behaviour. That's what we have been explaining so far to you. So here is an example illustrating a *few* things that can go wrong:
void testSleep(sf::Clock& clk) // <- notice the ref here?
// we need it because of your polymorphisme or we get sliced object
{
auto dt = 1s;
auto tolerance = 0.1;
auto t1 = clk.getElapsedTime();
sf::sleep(dt);
auto t2 = clk.getElapsedTime();
ensure(abs(t2-t1-dt) < tolerance);
}
void foo()
{
StopWatch stopwatch;
stopwatch.pause(); // <- because this could perfectly well happen in a full-fledged application
testSleep(stopwatch);
}
As you can see, you first of all need to edit some potentially existing code to take into account that sf::Clock can be derived or you get sliced object -- which you basically never want. This, Nexus has already mentioned: inheritance is part of the initial design and not added afterward or you get a flawed API. Such as here. Look at what will happen in the `testSleep`function: t1 and t2 will be the same value since the clock is paused. But this is no proper behaviour for a clock; on the contrary this means you have a failure with your clock, like a dead battery in your wall-clock. We don't want that, do we?
If you're thinking about OOP as a way to reduce the code duplication in your codebase, then you got it wrong. It might be true in Java were you have a different perspective on writing code, but in C++ we have many other paradigm than just OOP so we can use them to tackle different problems. For example we have free functions that can host code common to two unrelated classes, if needed.
Ah, there, a valid response to the actual topic.
Which is just a rephrasing of what I said in the first answer to your proposal...
This is an invalid rebuttal, however, because SFML has often changed things that go on to break user's code - for example, shifting the naming convention from UpperCase style to lowerUpperCase style, the removal of rand etc. I think generally, as a rule, when one uses a codebase under development, they have to expect code breaking changes.
Your reasoning is flawed in two places at least: a) you're comparing SFML 1 and SFML 2 -- like you could be comparing apples and oranges, this is wrong -- and b) SFML 2's API is
stable -- which means the user can expect his/her code to remain valid until he updates to SFML 3.
As a library maintainers, we
have to provide some kind of stability or no decent user will use our tools. That's a fact. And when we really want to change the behaviour of some function, or the naming convention for that matter, we need to bump the major version of the library. That's how it work out there.
I think not wanting to change something because it might break code isn't legitimate here
You can ask any library maintainer, they will all tell you the same thing. Bluntly put: you're wrong. Why? Read our answers again.
Listen, we're kinda circling around here. Your proposal is to change *all* private member functions to protected. We have shown you one *counterexample* and given you actual arguments as to why this would be bad both for us, maintainers, and you, users. If you want your proposal to be accepted, you'll need to prove that our arguments are invalid -- which is not the same as adding extra arguments.