C++ interface without virtual functions
It appears that you want to implement concepts (lite). You may want to read the article before attempting an implementation.
Absent compiler support, you can partially implement this idea. Your static_assert
idea is a known way to express interface requirements.
Consider the Sortable
example from the link. You can create a class template Sortable
, use static_assert
to assert all kind of thinks about the template parameter. You explain to your users that they need to implement a certain cet of methods, and to enforce that set is implemented, they need to make use of Sortable<TheirClass>
one way or another.
In order to express, right in a function declaration. the idea that your function requires a Sortable
, you will have to resort to something like this:
template <typename Container>
auto doSomethingWithSortable (Container&) -> std::enable_if<Implements<Container, Sortable>>::type;
Generating an interface without virtual functions?
You can use free functions to model the drawable
aspect of your objects:
#include <iostream>
class Image { };
class Sprite { };
class Model3D { };
namespace draw_aspect
{
void draw(Image const& image) { std::cout << "drawing image\n"; }
void draw(Sprite const& sprite) { std::cout << "drawing sprite\n"; }
void draw(Model3D const& model3D) { std::cout << "drawing model3D\n"; }
}
Now, either use three separate vectors (this could well be most optimal, depending on the ordering relationship between the objects across collections?), or consider a variant type vector:
1. Using variant types
#include <boost/variant.hpp>
using SceneObject = boost::variant<Image, Sprite, Model3D>;
namespace draw_aspect {
struct draw_visitor : boost::static_visitor<> {
template <typename T> void operator()(T const& t) const { draw(t); }
};
void draw(SceneObject const& sobj) {
static const draw_visitor _vis;
boost::apply_visitor(_vis, sobj);
}
}
A complete proof of concept of the latter: Live on Coliru
#include <vector>
class SceneManager //controls everything in the "world" game
{
public:
void Add(SceneObject v) { _worldObjects.emplace_back(std::move(v)); }
friend void draw(SceneManager const& sm) { return sm.draw(); }
private:
void draw() const {
for(auto& sobj : _worldObjects)
draw_aspect::draw(sobj);
}
std::vector<SceneObject> _worldObjects; //the vector that contains all of them
};
int main()
{
SceneManager sman;
sman.Add(Image());
sman.Add(Sprite());
sman.Add(Model3D());
sman.Add(Image());
draw(sman);
}
Outputs
drawing image
drawing sprite
drawing model3D
drawing image
2. Separate collections
The alternative using separate vectors: Live on Coliru
class SceneManager //controls everything in the "world" game
{
public:
void Add(Image v) { _images .emplace_back(std::move(v)); }
void Add(Sprite v) { _sprites .emplace_back(std::move(v)); }
void Add(Model3D v) { _model3Ds.emplace_back(std::move(v)); }
friend void draw(SceneManager const& sm) { return sm.draw(); }
private:
void draw() const {
for(auto& sobj : _images) draw_aspect::draw(sobj);
for(auto& sobj : _sprites) draw_aspect::draw(sobj);
for(auto& sobj : _model3Ds) draw_aspect::draw(sobj);
}
std::vector<Image> _images;
std::vector<Sprite> _sprites;
std::vector<Model3D> _model3Ds;
};
int main()
{
SceneManager sman;
sman.Add(Image());
sman.Add(Sprite());
sman.Add(Model3D());
sman.Add(Image());
draw(sman);
}
Note that the output is different (ordering):
drawing image
drawing image
drawing sprite
drawing model3D
Statically-enforcing a C++ class interface without using virtual methods
If you need to enforce your programmers to hide a base class member function by implementing a function of the same name in the derived class.... then leave the base class member function undefined. Attempts to call it will result in linker errors and build failure.
If your users don't try to call the function then the build will still work, which is not necessarily true of virtual functions. But do you care about that?
struct Parent
{
void mustDefine();
};
struct Child : Parent
{
// Link failure if this is missing, due to call in main().
// That's because, without Child::mustDefine() hiding
// Parent::mustDefine(), lookup for `mustDefine` will find
// Parent::mustDefine() instead... which is, well, undefined.
void mustDefine() {}
};
int main()
{
Child c;
c.mustDefine();
}
Abstract class as an interface, without the vtable
As it was already mentioned in the comments you can use the CRTP (aka static polymorphism) to avoid creation of a vtable:
template <typename Der>
class Base {
public:
Base() {}
~Base() {};
int thisMustBeDefined() {
// Will fail to compile if not declared in Der
static_cast<Der*>(this)->thisMustBeDefined();
}
int thisCouldBeOverwritten() { return 10; }
int thisWillBeUsedAsIs() { return 999; }
};
class Derived : public Base<Derived> {
public:
Derived() {}
~Derived() {}
int thisMustBeDefined() { return 11; }
// Works since you call Derived directly from main()
int thisCouldBeOverwritten() { return 20; }
};
To make compiler errors more readable if a function is not implemented in Derived
you can use a simple static check like provided in this answer:
#define DEFINE_HAS_SIGNATURE(traitsName, funcName, signature) \
template <typename U> \
class traitsName \
{ \
private: \
template<typename T, T> struct helper; \
template<typename T> \
static std::uint8_t check(helper<signature, &funcName>*); \
template<typename T> static std::uint16_t check(...); \
public: \
static \
constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t); \
}
DEFINE_HAS_SIGNATURE(thisMustBeDefined, T::thisMustBeDefined, int(*)(void));
and add the static check to the Base
constructor:
Base() {
static_assert(thisMustBeDefined<Der>::thisMustBeDefined,
"Derived class must implement thisMustBeDefined");
}
Though one drawback you should consider when working on a small device, and you have more versions of Derived
at a time is that the code in Base
will be duplicated for each Derived
instance.
So you have to decide if what's the more important limitation for your use case.
As @ChrisDrew pointed out in their comment, moving the thisCouldBeOverwritten()
and thisWillBeUsedAsIs()
functions to another base class that the Base
template class derives from would facilitate that problem.
How do you declare an interface in C++?
To expand on the answer by bradtgmurray, you may want to make one exception to the pure virtual method list of your interface by adding a virtual destructor. This allows you to pass pointer ownership to another party without exposing the concrete derived class. The destructor doesn't have to do anything, because the interface doesn't have any concrete members. It might seem contradictory to define a function as both virtual and inline, but trust me - it isn't.
class IDemo
{
public:
virtual ~IDemo() {}
virtual void OverrideMe() = 0;
};
class Parent
{
public:
virtual ~Parent();
};
class Child : public Parent, public IDemo
{
public:
virtual void OverrideMe()
{
//do stuff
}
};
You don't have to include a body for the virtual destructor - it turns out some compilers have trouble optimizing an empty destructor and you're better off using the default.
Is it possible to create an interface without using dynamic dispatch?
You have only one class, so there is no polymorphism by definition. You don't need inheritance, interfaces, CRTP, or any such hacks.
class SHTHumiditySensor /* no ': public HumiditySensor' needed */ {
private:
SHTSensor &sht;
public:
explicit SHTHumiditySensor(SHTSensor *sht);
void readSample() /* no virtual, no override */;
double getHumidity() const /* no virtual, no override */;
double getTemperature() const /* no virtual, no override */;
};
using HumiditySensor = SHTHumiditySensor;
No Virtual Function Table for abstract class?
These "interfaces" abstract classes probably have need no user written code in any their constructors and destructors (these either have an empty body and no ctor-init-list, or simply are never user defined); let's call these pure interface classes.
[Pure interface class: concept related but not identical to Java interfaces that are (were?) defined as having zero implementation code, in any member function. But be careful with analogies, as Java interfaces inheritance semantic isn't the same as C++ abstract classes inheritance semantic.]
It means that in practice no used object ever has pure interface class type: no expression ever refers to an object with pure interface type. Hence, no vtable is ever needed, so the vtable, which may have been generated during compilation, isn't included in linked code (the linker can see the symbol of the pure interface class vtable isn't used).
Related Topics
(Partially) Specializing a Non-Type Template Parameter of Dependent Type
Understanding Return Value Optimization and Returning Temporaries - C++
How to Iterate Over a Priority_Queue
Pure Virtual Functions May Not Have an Inline Definition. Why
What's the Difference Between Long Long and Long
Printing Prime Numbers from 1 Through 100
How to Use Source_Location in a Variadic Template Function
Default Argument in the Middle of Parameter List
Launch Failed. Binary Not Found. Cdt on Eclipse Helios
Most Efficient/Elegant Way to Clip a Number
C++: Where to Initialize Variables in Constructor
Can Lambda Functions Be Templated
How Do We Explain the Result of the Expression (++X)+(++X)+(++X)