Is there a way to prevent a base class method from being called on an instance of a derived class?

StackOverflow https://stackoverflow.com/questions/21920595

  •  14-10-2022
  •  | 
  •  

Domanda

I have a base class with a bunch of functionality and a derived class that extends that class but there are a few methods in the base class that don't make sense on the derived class.

Is it possible to do something to prevent these method(s) from being used by the derived class?

Class A
{
   ...

   public:
      void SharedMethod();
      virtual void OnlyMakesSenseOnA();
}

Class B : public Class A
{
   ...

   public:
      void OnlyMakesSenseOnB();
}

The following obviously doesn't work but is it possible to do something similar so that the compiler doesn't allow a certain base class method to be called?

Class B : public Class A
{
   ...

   public:
      void OnlyMakesSenseOnA() = 0;
}
È stato utile?

Soluzione

No, and this is completely wrong. If the member function is not callable in the derived type you are breaking the Liskov Substitution Principle. Consider whether this is the correct inheritance relationship. Maybe you want to extract SharedMethod to a real base and provide two separate unrelated A and B types.

Altri suggerimenti

This isn't as easy of an answer as I had hoped, but a coworker suggested that this situation is an indication of bad design and that I should re-think my inheritance structure by adding a new base class that only contains common functionality:

Class Base
{
   ...

   public:
      void SharedMethod();
}

Class A : public Base
{
   ...

   public:
      void OnlyMakesSenseOnA();
}

Class B : public Base
{
   ...

   public:
      void OnlyMakesSenseOnB();
}

Edit: Thanks to @David for providing a name for the rule that I'm trying to break. B is not a "Behavioural Subtype" of A because it fails the "counterfeit test". Therefore, deriving B from A violates the Liskov Subtitution Principle.

According to this slide deck, the counterfeit test is as follows:

  • Suppose I promise to deliver you an object of class T, but instead I give you an object x of class S.
  • You can subject x to any series of method calls you like (chosen from T’s signature).
  • If x behaves in a way that is not expected of a T object, then you know it is a counterfeit, x has failed the test.
  • If all S objects always pass every counterfeit test, then S is a behavioural subtype of T.

You could also just throw an exception if the invalid method is called on the derived class. It doesn't catch the bug at compile time but at least it prevents it from accidentally being used a runtime.

Class B : public Base
{
   ...

   public:
      void OnlyMakesSenseOnA() { throw Exception(); }
}

Yes, it's possible and quite simple, if we're talking about an external call. You can hide parent's method with private methods of derived class. Works with the static methods as well.

Tested on cpp 98, 11, 14. Try yourself in C++ shell.


class Base{
public:
  void methodBase(){};
  static void methodBaseStatic(){};
};

class Derived : public Base{
//private: //(private on default)
  void methodBase(){};
  static void methodBaseStatic(){};
};

Normal operation:

int main()
{
  Base b;
  
  b.methodBase();
  Base::methodBaseStatic();
  
  Derived d;

  return 0;
}

Compilation error

int main()
{
  Derived d;
  
  d.methodBase();
  
  Derived::methodBaseStatic();
  
  return 0;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top