Force All Classes to Implement/Override a 'Pure Virtual' Method in Multi-Level Inheritance Hierarchy

Force all classes to implement / override a 'pure virtual' method in multi-level inheritance hierarchy

I found one mechanism, where at least we are prompted to announce the overridden method explicitly. It's not the perfect way though.

Suppose, we have few pure virtual methods in the base class B:

class B {
virtual void foo () = 0;
virtual void bar (int) = 0;
};

Among them, suppose we want only foo() to be overridden by the whole hierarchy. For simplicity, we have to have a virtual base class, which contains that particular method. It has a template constructor, which just accepts the type same as that method.

class Register_foo {
virtual void foo () = 0; // declare here
template<typename T> // this matches the signature of 'foo'
Register_foo (void (T::*)()) {}
};
class B : public virtual Register_foo { // <---- virtual inheritance
virtual void bar (int) = 0;
Base () : Register_foo(&Base::foo) {} // <--- explicitly pass the function name
};

Every subsequent child class in the hierarchy would have to register a foo inside its every constructor explicitly. e.g.:

struct D : B {
D () : Register_foo(&D::foo) {}
virtual void foo () {};
};

This registration mechanism has nothing to do with the business logic. Though, the child class can choose to register using its own foo or its parent's foo or even some similar syntax method, but at least that is announced explicitly.

In a multi-level inheritance, does a grandchild require to implement a pure virtual method, if its parent has already implemented it?

Parent's start() is enough.

You should though use the override keyword for B's reimplementation :

class B : public A {
public: void start() override;
};

It makes it clear that the method is an implementation of a virtual one and the compiler will enforce that it will always be the case, even with future changes on class A.

How to force all derived classes to implement a virtual method?

Using curiously recurring template fun, you can achieve something quite similar:

template<typename T>
class Cloneable : public T, public Dep
{
private:
Cloneable<T>() : T() { }
public:
static Cloneable<T>* Create() { return new Cloneable<T>(); }
Cloneable<T>* clone() { return new Cloneable<T>(*this); }
};

Instead of deriving from Dep and instantiating via new MyType, use Cloneable<MyType>::Create. Since Cloneable<MyType> is derived from MyType, you can use the instance the same way you would use any MyType, except that it is now guaranteed to have Dep::clone.

Additionally your Master should not accept an instance of type Dep, but enforce that it is a Cloneable<T>. (Replace your orignial function by a simple function template that enforces this.) This guarantees that any Dep inside the master has a correctly implemented clone function.

Since Cloneable<MyType> has no public constructor, it cannot be inherited, however your actual MyType can be further inherited and used just as before.

Multilevel Inheritance and Pure Virtual Functions

class Grand_Son:public Son {
public:
---^^^^^^^
void foo() {
cout<<"\nFunction foo From Grand_Son\n";
}
};

You haven't declared foo public - I added it above.

Force a derived class to override one of a set of virtual functions

No, but you can fake it.

Base has non-virtual float and int methods that forward to a pure virtual std variant one.

Two helper classes, one int one float, implement the std variant one, forwarding both cases to either a pure virtual int or float implementation.

It is in charge of dealing with the 'wrong type' case.

Derived inherit from one or another helper, and implement only int or float.

struct Base
{
void function1(int x) { vfunction(x); }
void function2(float x) { vfunction(x); }
virtual void vfunction(std::variant<int,float>) = 0;
};
struct Helper1:Base {
void vfunction(std::variant<int,float> v) final {
if (std::holds_alternative<int>(v))
function1_impl( std::get<int>(v) );
}
virtual void function1_impl(int x) = 0;
};
struct Helper2:Base {
void vfunction(std::variant<int,float> v) final {
if (std::holds_alternative<float>(v))
function2_impl( std::get<float>(v) );
}
virtual void function2_impl(float x) = 0;
};

struct Derived1 : Base {}; // ERROR not implemented
struct Derived2 : Helper1 { void function1_impl(int) override; }; // OK
struct Derived3 : Helper2 { void function2_impl(float) override; }; // OK

This uses https://en.wikipedia.org/wiki/Non-virtual_interface_pattern -- the interface contains non-virtual methods, whose details can be overridden to make them behave differently.

If you are afraid people will override vfunction you can use the private lock technique, and/or just give it a name like private_implementation_detail_do_not_implement and trust your code review process.

Turning a non-pure virtual function into pure in a subclass

You're fine if implemented as you present in your explanation. Without going into entire sections on abstract base classes and virtual functions, the standard dictates:

C++ § 10.4p2

An abstract class is a class that can be used only as a base class of some other class; no objects of an abstract class can be created except as subobjects of a class derived from it. A class is abstract if it has at least one pure virtual function. [ Note: Such a function might be inherited: see below. — end note ] A virtual function is specified pure by using a pure-specifier (9.2) in the function declaration in the class definition. A pure virtual function need be defined only if called with, or as if with (12.4), the qualified-id syntax (5.1)

The "below" referenced above leads to this note:

C++11 § 10.4p5

[Note: An abstract class can be derived from a class that is not abstract, and a pure virtual function may override a virtual function which is not pure. - end note]

Require override of parent virtual function

There's no easy way of doing so in C++.

There is a hack though, explained in this answer, using virtual inheritance and forcing your classes to register which serialize method they are using.



Related Topics



Leave a reply



Submit