We have a special framework for interfaces in our project, and part of the requirements is that classes which represent an interface may only be used as virtual base classes, not as non-virtual ones. Is there a way to enforce this in code? That is, produce a compilation error if the class is derived from non-virtually.
I have access to C++11 as implemented by VS 2010: this means static_assert, enable_if and <type_traits> are available.
IMO, there is no clean and platform independent solution available to this problem.
The best way is to manually go and change each and every inheritance to virtual inheritance.
To accomplish that, identifying the derived classes of your interface (say class Base) is easy(!). Below steps can be followed for that:
Make class Base as final (c++11); i.e. class Base final { ...
Compile the code, it will generate compiler error for all its
derived classes
Go and check every derived class and make the inheritance as
virtual
Remove the final keyword and compile the code successfully
This process (unfortunately) has to be followed periodically, whenever you want to do such sanity checking.
This is possible to check at compile time. The key is that, if we have a diamond pattern:
You can unambiguously cast D& to A&. However, if the inheritance is non-virtual:
the cast would ambiguous. So let's try to make a diamond!
template <typename Base, typename Derived>
class make_diamond {
struct D2 : virtual Base { }; // this one MUST be virtual
// otherwise we'd NEVER have a diamond
public:
struct type : Derived, D2 { };
};
At which point it's just another void_t-style type trait:
template <typename Base, typename Derived, typename = void>
struct is_virtual_base_of : std::false_type { };
template <typename Base, typename Derived>
struct is_virtual_base_of<Base, Derived, void_t<
decltype(static_cast<Base&>(
std::declval<typename make_diamond<Base, Derived>::type&>()))
>> : std::true_type { };
If the cast is unambiguous, the expression in the partial specialization will be valid, and that specialization will be preferred. If the cast is ambiguous, we'll have a substitution failure, and end up with the primary. Note that Base here doesn't actually need to have any virtual member functions:
struct A { };
struct B : public A { };
struct C : virtual A { };
std::cout << is_virtual_base_of<A, B>::value << std::endl; // 0
std::cout << is_virtual_base_of<A, C>::value << std::endl; // 1
And if it has any pure virtual member functions, we don't have to override them since we're never actually constructing an object.
struct A2 { virtual void foo() = 0; };
struct B2 : public A2 { void foo() override { } };
struct C2 : virtual A2 { void foo() override { } };
std::cout << is_virtual_base_of<A2, B2>::value << std::endl; // 0
std::cout << is_virtual_base_of<A2, C2>::value << std::endl; // 1
Of course if your class is marked final, this won't work at all. But then, if it were final, it wouldn't matter what kind of inheritance it had anyway.
Interesting problem. You may be able to get close to what you want by hiding the interface class and exposing a concrete class that inherits from the interface virtually. This obviously entails some workarounds and awkwardness, but it might be adaptable to your needs. Here's an example:
#include <iostream>
using namespace std;
class Hide {
struct VInterface {
void foo() const { cout << "VInterface::foo()\n"; }
VInterface const &as_interface() const { return *this; }
protected:
virtual ~VInterface() { }
};
public:
struct VBase : virtual VInterface {
};
};
typedef Hide::VBase VBase;
struct VDiamond1 : VBase { };
struct VDiamond2 : VBase { };
struct VConcrete : VDiamond1, VDiamond2 { };
int main() {
VConcrete vc;
auto const &vi = vc.as_interface();
vi.foo();
}
It may be possible to reconstruct a name using decltype() and as_interface() that may be usable for inheritance, but the ones I tried resulted in compiler errors that the destructor was protected, so I expect that if it is possible, it's at least relatively difficult and might be sufficient for your needs.
Related
UPDATE: the behaviour is not template specific, so
struct Derived : public Base {
OverrideFoo* m_data {new OverrideFoo()};
}
will do the same. so it seems m_data in Derived and m_data in Base both exist in memory layout. If we define a function in Derived,
e.g., Derived::print() { m_data->print()}, this will use m_data in Derived, however, if base function is called on derived object, it still use m_data from Base.
I was surprised with the behaviour of the following code, it prints "from foo", rather than the "from override foo". why is it like this? shouldn't the "m_data" be the type of "OverrideFoo"?
#include <iostream>
using namespace std;
struct Foo {
void print() {
printf("from foo\n");
}
};
struct OverrideFoo {
void print() {
printf("from override foo\n");
}
};
struct Base {
void useData() {
m_data->print();
}
Foo* m_data {new Foo()};
};
template <class t>
struct Derived : public Base {
t* m_data {new t()};
};
int main()
{
Derived<OverrideFoo> d;
d.useData();
return 0;
}
When you call d.useData(), you are calling Base::useData(), which accesses Base::m_data.
I suppose you're expecting Base::useData() to use Derived::m_data, just because the variable has a similar name. However that's not how this works. Both classes get their own independent m_data, and in your case, with different types.
It's true that Derived::m_data hides Base::m_data, which may suggest to you that they are related or that one "overrides" the other. Don't confuse that with hiding. The hiding is a natural consequence of the similar naming. If Derived needs to access Base::m_data, it must qualify it in order to disambiguate from its own m_data.
Note: Member variables / fields cannot be overridden. If you need an override-style behavior, you'll need to do it via a member function (something like virtual IPrintable* GetPrintable(). And the base class must grant the possibility of overriding with the virtual keyword.
Another way to think about this: Base, despite what its name suggests, is a complete type. You can do Base x; to instantiate and use this class, without being derived. The compiler generates code for Base which is complete and functional, including the code to access Base::m_data. If m_data were somehow overrideable, how could this code be generated? What would Base understand sizeof(*m_data) to be, if its datatype could be overridden in some base class? How would the compiler know what m_data even refers to, if you're suggesting it can be changed by any class which derives it?
Another point: If members were able to be overridden by default (without the virtual keyword), it would cause mass chaos for base classes. Imagine writing a generic base class and risking that derived classes could unknowingly change the state of the base? Or imagine writing a derived class and being concerned about your variable naming because "well maybe a base class used the same name?"
So let's summarize the key points:
Fields cannot be overridden, period. It would break sizeof() among lots of other things (whole other topic)
Base classes must explicitly grant derived classes to override member functions via the virtual keyword.
There are probably better ways to do what you're attempting though. The most natural for me would be to specify the Foo type as a template parameter to Base.
Like this:
struct Foo1 {
void print() {
printf("from foo\n");
}
};
struct Foo2 {
void print() {
printf("from override foo\n");
}
};
template<typename TData>
struct Base {
void useData() {
m_data.print();
}
TData m_data;
};
template <typename TData>
struct Derived : public Base<TData> {
};
int main()
{
Derived<Foo1> d1;
d1.useData();
Derived<Foo2> d2;
d2.useData();
return 0;
}
It's hard to know the best approach for you, because this is an unrealistic contrived example.
Try this code out and you will find that the two m_data has different memory address, which means they are different variable.
#include <iostream>
using namespace std;
struct Foo {
void print() {
printf("from foo\n");
}
};
struct OverrideFoo {
void print() {
printf("from override foo\n");
}
};
struct Base {
void useData() {
m_data->print();
std::cout << m_data << std::endl;
}
Foo* m_data {new Foo()};
};
template <class t>
struct Derived : public Base {
t* m_data {new t()};
};
int main()
{
Derived<OverrideFoo> d;
d.useData();
d.m_data->print();
std::cout << d.m_data << std::endl;
return 0;
}
I'd like to make an abstract class that defines some methods of a class. Some of these should be implemented by the base class (Base), some should be defined in Base but overwritten by Derived and others should be pure virtual in Base to force definition in Derived.
This is of course what abstract classes are for. However, my application will only ever use the Derived object directly. Because of this, the compiler should know at compile-time exactly which methods are to be used.
Now, because this code will run on a microcontroller with very limited RAM, I'm keen to avoid actually using a virtual class with the vtable this entails. From my testing it seems that the compiler is smart enough to not make a vtable unless it has to, at least in some circumstances. However I've been told to never trust the compiler: is it possible to make this a required condition of compilation?
Here are some code examples:
Classes
class Base {
public:
Base() {}
virtual ~Base() {};
virtual int thisMustBeDefined() = 0;
virtual int thisCouldBeOverwritten() { return 10; }
int thisWillBeUsedAsIs() { return 999; }
};
class Derived : public Base {
public:
Derived() {}
~Derived() {}
int thisMustBeDefined() { return 11; }
};
No vtable
This has no vtable and is what I want
int main() {
Derived d;
d.thisMustBeDefined();
}
Yes vtable 1
As a result of my sloppy coding, I've mistakenly forced the compiler to use polymorphism and therefore to require a vtable. How can I make this case throw an error?
int main() {
Base * d;
d = new Derived();
d->thisMustBeDefined();
}
Yes vtable 2
Here I've not refered to the class "Base" at any point, so the compiler should know that all the methods are pre-determined at compile time. However it still creates a vtable. This is another example of why I want to be able to detect this with a compile error.
int main() {
Derived * d;
d = new Derived();
d->thisMustBeDefined();
}
In other words, I want it to be a compiler error if I write code that results in the compiler producing a vtable for my classes, i.e. uses polymorphism.
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.
I'm making a base class, which has some methods, which are used in derived classes. This base class is something like an abstract class in the sense that apart from (protected) methods, it defines the interface (i.e. public) methods which must be implemented in derived classes. But it's not intended to be used as a polymorphic base, instead its derivatives will be used as template parameters for some other functions/functors, which would call the interface methods.
Given the above, I could use the usual way of defining abstract classes like using pure virtual functions, but there's a problem with this: the resulting derivative classes are required to have standard layout. Thus no virtual functions allowed. But still there'll be many derivatives, which will not be used until some later time, and I'd like to make the compiler check that all the methods required are implemented with the correct signature (e.g. int Derived::f(double) instead of int Derived::f(float) is not allowed).
What would be a good way to do this, taking into account the requirement of standard layout?
Here's an implementation of the CRTP pattern with a static_assert inside the interface dispatching routine:
#include <iostream>
#include <type_traits>
template<class Derived>
class enable_down_cast
{
typedef enable_down_cast Base;
public:
// casting "down" the inheritance hierarchy
Derived const* self() const { return static_cast<Derived const*>(this); }
Derived* self() { return static_cast<Derived* >(this); }
protected:
// disable deletion of Derived* through Base*
// enable deletion of Base* through Derived*
~enable_down_cast() = default;
};
template<class FX>
class FooInterface
:
public enable_down_cast< FX >
{
using enable_down_cast< FX >::self; // dependent name now in scope
public:
int foo(double d)
{
static_assert(std::is_same<decltype(self()->do_foo(d)), int>::value, "");
return self()->do_foo(d);
}
protected:
// disable deletion of Derived* through Base*
// enable deletion of Base* through Derived*
~FooInterface() = default;
};
Note that the above static_assert only fires if the return types of the interface and the implementation don't match. But you can decorate this code with any type trait you wish, and there are plenty of Q&As here on SO that write type traits to check for an exact function signature match between interface and implementation.
class GoodFooImpl
:
public FooInterface< GoodFooImpl >
{
private:
friend class FooInterface< GoodFooImpl > ;
int do_foo(double) { std::cout << "GoodFooImpl\n"; return 0; }
};
class BadFooImpl
:
public FooInterface< BadFooImpl >
{
private:
friend class FooInterface< BadFooImpl >;
char do_foo(double) { std::cout << "BadFooImpl\n"; return 0; }
};
int main()
{
GoodFooImpl f1;
BadFooImpl f2;
static_assert(std::is_standard_layout<GoodFooImpl>::value, "");
static_assert(std::is_standard_layout<BadFooImpl>::value, "");
f1.foo(0.0);
f2.foo(0.0); // ERROR, static_assert fails, char != int
}
Live Example on Coliru. Note that the derived class is indeed standard layout.
Given a base class Base that has two derived classes, DerA and DerB, can the derived classes have a member variable that is used in a Base member function, but is a different type for each class?
class Base {
* a // Declare a as *something*, so it can be used by "doWork"
template <typedef T>
void doWork(T b) { // Add another value to "a" which is of its same type
a += b; // For example; an operation that works on "a", no matter what numeric type it is
}
}
class DerA : public Base {
// Make "a" an int
}
class DerB : public Base {
// Make "a" a float
}
In practice, a will be a base struct, while DerA and DerB will have derived versions of the base struct (derivative classes will each have a derived form of the struct specific to their purpose, but each must do a simple operation on a, so it seems pointless to copy/paste that simple function for each derivative when I can just use a template function). I would just type a as the base struct type, but then I lose access to the various specialized member functions and variables that each derived struct has (if I understand inheritance correctly).
I apologize if this question is a repeat, but I don't know what this quality would be called, so Googling proved fruitless.
What you might want is the CRTP.
template<class D>
struct Base {
D* self() { return static_cast<D*>(this); }
D const* self() const { return static_cast<D*>(this); }
template<class T>
void doWork(T b) {
self()->a += b;
}
};
struct DerA : public Base<DerA> {
int a;
};
struct DerB : public Base<DerB> {
double a;
};
Here we pass the derived type to our base class. Within the base class, you can use self()-> to access fields in the derived type. This allows basically full access to the derived type, while letting us share code in the base class.
Note that you cannot pass DerA and DerB around as a Base this way. If you want that, you need a virtual method doWork, and virtual template methods don't exist.
CRTP stands for the curiously repeating template pattern, which I imagine is named because it is strange, it involves repeating a type, and it keeps on showing up in strange corners as being useful.
Type erasure probably won't work either, as you want to dispatch the type erasure from two different spots in the code base (the double dispatch problem: you need a centralized list of types supported to do the type Cartesian product on).
To expand on that, in order to support a+=b where both a and b are arbitrary types, you would have to expand over all types twice over, including types that are never mutually visible at the same spot in a compilation unit. That isn't possible.
If you need a common base, and there are only some types you pass to doWork, here is how you do it:
struct Base {
virtual void doWork( double ) = 0;
virtual void doWork( int ) = 0;
virtual void doWork( long long ) = 0;
};
template<class D>
struct Base_helper:Base {
D* self() { return static_cast<D*>(this); }
D const* self() const { return static_cast<D*>(this); }
template<class T>
void doWork_impl(T b) {
self()->a += b;
}
void doWork( double x ) override { doWork_impl(x); };
void doWork( int x ) override { doWork_impl(x); };
void doWork( long long x ) override { doWork_impl(x); };
};
struct DerA : public Base_helper<DerA> {
int a;
};
struct DerB : public Base_helper<DerB> {
double a;
};
note that every version of doWork must be valid to call on each of the Ders, as the Base_helper instantiates all of them.
If the kind of type passed to doWork is unbounded, yet the types of Der is bounded, you can do something like the above only backwards. It gets awkward, however. Your best bet in that kind of situation is to use a boost::variant type solution.
I guess you want to achieve something like this:
template<typedef T>
class Base {
T a;
void doWork(T b) { // Add another value to "a" which is of its same type
a += b; // For example; an operation that works on "a", no matter what numeric type it is
}
}
class DerA : public Base<int> {
}
class DerB : public Base<float> {
}
Or you can dump classes DerA and DerB entirely and use typedefs instead:
typedef Base<int> DerA;
typedef Base<float> DerB;
This can be easily solved with a CRTP-like pattern:
template<class D> // Base class is templated
class Base {
public:
D a;
void doWork(D b) {
a += b;
}
};
class DerA : public Base<int> {};
class DerB : public Base<float> {};
Live Example
Edit: in case you need only one common base (Base<int> is a completely different type from Base<float>) you might use an interface class and have Base inherit from it.
In CRTP to avoid dynamic polymorphism, the following solution is proposed to avoid the overhead of virtual member functions and impose a specific interface:
template <class Derived>
struct base {
void foo() {
static_cast<Derived *>(this)->foo();
};
};
struct my_type : base<my_type> {
void foo() {}; // required to compile. < Don't see why
};
struct your_type : base<your_type> {
void foo() {}; // required to compile. < Don't see why
};
However it seems that the derived class does not require a definition to compile as it inherits one (the code compiles fine without defining a my_type::foo). In fact if a function is provided, the base function will not be called when using the derived class.
So the question is, is the following code replacement acceptable (and standard?):
template <class Derived>
struct base {
void foo() {
// Generate a meaningful error if called
(void)sizeof( Derived::foo_IS_MISSING );
};
};
struct my_type : base<my_type> {
void foo() {}; // required to compile.
};
struct your_type : base<your_type> {
void foo() {}; // required to compile.
};
int main() {
my_type my_obj;
my_obj.foo(); // will fail if foo missing in derived class
}
The whole point of this pattern is, as far as I understand, that you can pass arguments simply as template <typename T> base<T> & and your interface is defined by (non-virtual) functions in base<T>. If you don't have an interface that you want to define (as you are suggesting in the second part of your question), then there's no need for any of this in the first place.
Note that you are not "imposing" an interface like with pure virtual functions, but rather you are providing an interface. Since everything is resolved at compile time, "imposing" isn't such a strong requirement.
In your replacement code you can't "polymorphically" call foo on a base<T>.
However it seems that the derived class does not require a definition to compile as it inherits one (the code compiles fine without defining a my_type::foo).
C++ is lazy : it will not try to make base<my_type>::foo() if you do not actually use it.
But if you try to use it, then it will be created and if that fails, compilation errors will flow.
But in your case, base<my_type>::foo() can be instanciated just fine :
template <class Derived>
struct base {
void foo() {
static_cast<Derived *>(this)->foo();
};
};
struct my_type : base<my_type> {};
void func() {
my_type m;
static_cast<base<my_type>& >(m).foo();
}
will compile just fine. When the compiler is presented with
static_cast(this)->foo(), it will try to find a foo() that is accessible in my_type. And there is one: it's called base<my_type>::foo(), which is public from a publicly inherited class. so base<my_type>::foo() calls base<my_type>::foo(), and you get an infinite recursion.
No, imagine the following situation:
template <typename T>
void bar(base<T> obj) {
obj.foo();
}
base<my_type> my_obj;
bar(my_obj);
Base's foo will be called instead of my_type's...
Do this, and you will get your erro message:
template <class Derived>
struct base {
void foo() {
sizeof(Derived::foo);
static_cast<Derived *>(this)->foo();
};
};
But I must confess I am not sure how this will work in compilers other than GCC, tested only with GCC.