Reputation: 2161
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
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();
}
}
Upvotes: 0
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
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
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