user6245072
user6245072

Reputation: 2161

How to make an inherited virtual function not usable?

I have an abstract base class which declares a pure virtual function (virtual method() = 0;). Some of the inherited classes specialize and use this method but there's one of those inherited classes in which I don't want to make this method usable. How do I do it? Is making it private the only choice?

Upvotes: 1

Views: 143

Answers (4)

Chris Drew
Chris Drew

Reputation: 15334

As others have said there is no way of enforcing this at compile time. If you are referring to a pointer to a base class there is no way the compiler can know if that pointer is referring to one of the derived classes that does implement this method or one that doesn't.

So the case will have to be handled at runtime. One option is to just throw an exception. Another option is to introduce a level of indirection so that you can ask your base class if it implements a certain function before you call it.

Say you have a Base class with three methods foo, bar and doit and some derived classes do not want to implement foo then you could split up the Base class into two base classes:

class Base1 {
    public:
        virtual void foo() = 0;
};

class Base2 {
    public:
        virtual void bar() = 0;
        virtual void doit() = 0;
};

Then in places where you are currently using Base you instead use a BaseSource:

class BaseSource {
    public:
        virtual Base1* getBase1() = 0;
        virtual Base2* getBase2() = 0;
};

where getBase1 and getBase2 can return nullptr if a BaseSource does not offer that interface:

class Derived : public BaseSource, public Base2 {
  public:   
     // don't implement foo();

     // Implemementation of Base2
     void bar() override;
     void doit() override;

     Base1* getBase1() override { return nullptr; } // Doesn't implement Base1
     Base2* getBase2() override { return this; }
};

int main() {
    std::vector<std::unique_ptr<BaseSource>> objects;
    objects.push_back(std::make_unique<Derived>());

    for (auto& o : objects) {
      auto b1 = o->getBase1();
      if (b1)
          b1->foo();
      auto b2 = o->getBase2();
      if (b2)
          b2->bar();
    }
}

Live demo.

Upvotes: 0

Guillaume Racicot
Guillaume Racicot

Reputation: 41750

Well, you could throw that will make tacking where it is called easier.

void method() override { throw /* whatever */ ; } 

Dynamic polymorphism is a runtime property. Hence a runtime error. If you look after something that will trigger at compile time, you need static polymorphism.

template<typename Child>
struct Parent {
    void callMe() {
        static_cast<Child*>(this)->callMeImpl();
    }
};

struct SomeChild : Parent<SomeChild> {

};

Now, if you try to call callMe form the parent that is extended by SomeChild, it will be a compile time error.

You can also hold pointer to the parent just like dynamic polymorphism, as the parent will call the child function

Upvotes: 1

Lourens Dijkstra
Lourens Dijkstra

Reputation: 430

I guess you could make it a normal virtual function instead of a pure virtual function like this:

virtual void method() { /* code */ } 

If this function is not being used in another class, you will be able to catch that. For example you could warn yourself:

virtual void method() { error = true; } //or whatever

Upvotes: 0

Bathsheba
Bathsheba

Reputation: 234635

Is making it private the only choice?

No, that's not a choice at all since you can still access the method if it's public or protected in the base classes.

Other than implementing the method in the class and resorting to run-time failures, there's not a lot you can do. You could port the whole thing to templates and use static polymorphism which, with further trickey, you could contrive a compile-time failure in certain instances, but that could be design overkill.

Upvotes: 0

Related Questions