5

Let's say I have a base class called Human. Baby and Adult are sub-classes of Human. Human has a function run as a pure virtual function and I don't want Baby to inherit run but if I don't override run, Baby would become an abstract class.

class Human{
 public:
   // Some human attributes.
   virtual void run()=0;
};

class Adult: public Human{
 public:
   void run(){
      // Adult running function
   }
};

class Baby: public Human{
 public:
   void run()=delete; //error

   // If I don't override `run` then Baby is marked as an abstract class

   void crawl(){
     // Baby crawling function.
   }
};

Error if I mark run with =delete

prog.cpp:19:10: error: deleted function ‘virtual void Baby::run()’
     void run()=delete;
          ^~~
prog.cpp:6:22: error: overriding non-deleted function ‘virtual void Human::run()’
         virtual void run()=0;
                      ^~~

Might be a bad example but what I want is to inherit everything except for run in Baby. Is it possible?


Disclaimer: I'm not implementing it anywhere. Just out of curiosity.

Ch3steR
  • 20,090
  • 4
  • 28
  • 58
  • If you want `Human` to be abstract and don't want `run` a pure virtual , declare destructor as pure virtual. – The Philomath Jan 15 '21 at 06:22
  • @ThePhilomath I can't comprehend how making destructor pure virtual solves allows suppressing `run` in `Baby`. I'm new to `c++` mind explaining elaborately and post it as an answer? – Ch3steR Jan 15 '21 at 06:36
  • 8
    If not all humans can run, than maybe that shouldn't be in their interface. LSP is worth keeping in mind here. – StoryTeller - Unslander Monica Jan 15 '21 at 06:37
  • Not possible because of the example in the answer. You can either leave is empty `void run(){}`, `throw` an error in there, or trigger an `assert`. Because this is dynamic polymorphism you can't do anything at compile time. – JHBonarius Jan 15 '21 at 06:40
  • I suspect this is an XY-problem. The whole *reason* that a base class provides a pure virtual function is to force derived classes to implement it, and ensure it can be called polymorphically. You can make the function `private` in the derived class to prevent `some_baby->run()` (where `some_baby` is of type `Baby *`) but it is still necessary to define it AND `Baby::run()` can still be executed polymorphically (e.g. `some_human->run()` will call `Baby::run()` if `some_human` actually points at an instance of `Baby`). – Peter Jan 15 '21 at 06:40
  • @Ch3steR: That was not an answer for your problem. I am suggesting an alternative so that `Baby` will not be forced to define `run` and `Human` remains an abstract class. – The Philomath Jan 15 '21 at 06:40
  • @StoryTeller-UnslanderMonica Yeah LSP makes sense. For those who are wondering abt [`LSP`](https://stackoverflow.com/questions/56860/what-is-an-example-of-the-liskov-substitution-principle) – Ch3steR Jan 15 '21 at 06:45
  • @Peter Thank you for your input. I'm not actually trying to solve anything with this but it is just out of curiosity. I was learning `=delete` and wondered if I can suppress a pure virtual function – Ch3steR Jan 15 '21 at 06:47
  • think of an abstract base class as an interface - like an actual interface some other people use to program against. **if** it would be possible to delete an interface function, your program would not conform to the interface. So why does Human have a `run()` function although not all humans should have it? – Raildex Jan 15 '21 at 07:20

1 Answers1

10

This is not possible. Consider the following code:

Human *CreateAPerson() {
  return new Baby();
}

int main() {
  Human *human = CreateAPerson();
  human->run();
}

The compiler would have no way to know that human->run() is illegal.

Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
  • Any way I can suppress `run` in `Baby`? – Ch3steR Jan 15 '21 at 06:22
  • @Ch3steR yes and no. Not with dynamic inheritance, pure base class and type erasure. Well, you can make it private, but it's still will be there. It will be able to run as a Baby but will be able as a Human, Something like that is kind of possibly using CRTP\mixins and "disabling" one or another method in derived classes but that would be a complex solution and in that case there must be some kind of default empty (returning an error state?) method. – Swift - Friday Pie Jan 15 '21 at 06:54
  • @Ch3steR add something like `assert(false)`. But I guess you should make another interface declaring virtual `run` (`Runnable`?) and don't inherit `Baby` from it. – fas Jan 15 '21 at 06:55