Date: Sun, 20 Mar 2022 13:27:38 -0400
On Sat, Mar 19, 2022 at 10:37 PM organicoman <organicoman_at_[hidden]> wrote:
>
> ```
> class base_class
> {
> public:
> virtual void foo() {}
> };
>
> class intermediary : public base_class
> {
> public:
> void foo() final {my_foo();}
>
> virtual my_foo() = 0;
> };
>
> class derived : public intermediary
> {
> public:
>
> };
>
> derived d; //Compile error due to unimplemented pure-virtual function.
> ```
> That's if your intention is to make 'intermediary' a non final product i.e unusable by end user without deriving, and obliging him to derive + implement before usage.
>
> Me , i want the code to run without imposing anything upon the end user, but nevertheless i want him to be aware of what's going on.
This does not make sense. If a derived class does not override a
virtual function, this is either correct or incorrect. If it is
correct for a derived class to not override that virtual function,
then it must be 100% valid for a user to call that virtual function.
There is nothing more "going on" than that. From the perspective of
the language, this ought to be a binary choice.
> Take the following case scenario:
>
> Imagine the virtual method in your 'base_class', is general enough and covers most needs of derived classes for that function. But in one or two derived classes you want to give the end user more introspection, and control over the implementation of that exact method. So usually, you derive from the base class, don't override the method in question to keep the general usage, but you provide two other member functions which will give you more fine tuned control of the implementation.
> So from the perspective of the end user, he sees that for more control, use the other member functions, and for the usual general usage the base method is the fall back, but he would never guess that the base method was not overrriden in the class he is using, and probably won't give him the results he expects, and without going back to the documentation he will never guess that shortage.
> So if the compiler gives him a heads-up "hey you are directly using the base class method, not the overrriden one", he will automatically investigate if the base class implementation of that method will cover his intended usage.
I don't understand this circumstance. Indeed, it sounds like a misuse of OOP.
The reason to have a virtual function is so that code can interact
with derived classes without *knowing* that they're interacting with
derived classes. The code in question accesses the derived class
through a base class interface.
This circumstance seems to be for the benefit of direct users of the
derived class. But those are not the only users of the type. There is
still code out there that will use the base class interface only and
such code will expect certain functionality out of calling that
interface.
So will your code do what the base class interface requires it to do?
Will it behave appropriately to such interfaces? If the answer is
"yes", then there is no reason why a user should not be able to call
the base class interface from a derived class. If the answer is
"no"... you are *lying* by claiming that your type has an "is-a"
relationship with the base class.
Basically, either your type is a base class or it isn't. The
circumstance you're outlining seems to suggest that it wants to have
it both ways. But you can't, and you *shouldn't*.
In short, I do not understand how this feature can be used in a manner
consistent with the Liskov Substitution Principle. And if you're
trying to violate that, then you're not really doing OOP.
Just to head things off at the pass, I do understand *what* you want.
I do not understand how it makes sense to *want* what you want, how it
represents good code design principles. Can you give a concrete
example of code where the following are simultaneously true:
1. The base class function does the right thing when called from code
that only uses the base class interface.
2. If you're using the derived class interface, calling the base class
function will *not* do "the right thing". So instead, you're expected
to call some other functions only available on the derived class.
>
> ```
> class base_class
> {
> public:
> virtual void foo() {}
> };
>
> class intermediary : public base_class
> {
> public:
> void foo() final {my_foo();}
>
> virtual my_foo() = 0;
> };
>
> class derived : public intermediary
> {
> public:
>
> };
>
> derived d; //Compile error due to unimplemented pure-virtual function.
> ```
> That's if your intention is to make 'intermediary' a non final product i.e unusable by end user without deriving, and obliging him to derive + implement before usage.
>
> Me , i want the code to run without imposing anything upon the end user, but nevertheless i want him to be aware of what's going on.
This does not make sense. If a derived class does not override a
virtual function, this is either correct or incorrect. If it is
correct for a derived class to not override that virtual function,
then it must be 100% valid for a user to call that virtual function.
There is nothing more "going on" than that. From the perspective of
the language, this ought to be a binary choice.
> Take the following case scenario:
>
> Imagine the virtual method in your 'base_class', is general enough and covers most needs of derived classes for that function. But in one or two derived classes you want to give the end user more introspection, and control over the implementation of that exact method. So usually, you derive from the base class, don't override the method in question to keep the general usage, but you provide two other member functions which will give you more fine tuned control of the implementation.
> So from the perspective of the end user, he sees that for more control, use the other member functions, and for the usual general usage the base method is the fall back, but he would never guess that the base method was not overrriden in the class he is using, and probably won't give him the results he expects, and without going back to the documentation he will never guess that shortage.
> So if the compiler gives him a heads-up "hey you are directly using the base class method, not the overrriden one", he will automatically investigate if the base class implementation of that method will cover his intended usage.
I don't understand this circumstance. Indeed, it sounds like a misuse of OOP.
The reason to have a virtual function is so that code can interact
with derived classes without *knowing* that they're interacting with
derived classes. The code in question accesses the derived class
through a base class interface.
This circumstance seems to be for the benefit of direct users of the
derived class. But those are not the only users of the type. There is
still code out there that will use the base class interface only and
such code will expect certain functionality out of calling that
interface.
So will your code do what the base class interface requires it to do?
Will it behave appropriately to such interfaces? If the answer is
"yes", then there is no reason why a user should not be able to call
the base class interface from a derived class. If the answer is
"no"... you are *lying* by claiming that your type has an "is-a"
relationship with the base class.
Basically, either your type is a base class or it isn't. The
circumstance you're outlining seems to suggest that it wants to have
it both ways. But you can't, and you *shouldn't*.
In short, I do not understand how this feature can be used in a manner
consistent with the Liskov Substitution Principle. And if you're
trying to violate that, then you're not really doing OOP.
Just to head things off at the pass, I do understand *what* you want.
I do not understand how it makes sense to *want* what you want, how it
represents good code design principles. Can you give a concrete
example of code where the following are simultaneously true:
1. The base class function does the right thing when called from code
that only uses the base class interface.
2. If you're using the derived class interface, calling the base class
function will *not* do "the right thing". So instead, you're expected
to call some other functions only available on the derived class.
Received on 2022-03-20 17:28:02