Abstract class as an interface, without the vtable - c++

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.

Related

the member variable with the same name in derived class

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;
}

Changing member types in inheritance

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.

Force deriving from a class virtually

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.

Alternative to virtual static functions in c++?

In the header file .hpp:
class Base{
public:
static /*Some Return Type*/ func(/*Some Datatype*/);
}
class Derived1 public Base{
public:
Derived1();
~Derived1();
}
class Derived1 public Base{
public:
Derived2();
~Derived2();
}
In the cpp file .cpp:
/*Some Return Type*/ Derived1::func(/*Some Datatype*/){
}
/*Some Return Type*/ Derived2::func(/*Some Datatype*/){
}
This obviously fails because there is no way to override a static method in a subclass. But how to obtain the above functionality?
It is mandatory for me to call something like this:
/*Some Return Type*/ result = Derived1::func(/*Some Datatype*/)
/*Some Return Type*/ result = Derived2::func(/*Some Datatype*/)
I know, that abstract method can be defined in the base class like below and then define them in Derived class:
In the header file .hpp:
class Base{
public:
virtual /*Some Return Type*/ func(/*Some Datatype*/) const = 0;
}
But the problem is that virtual methods require object instantiation, which is not I want. I want to call the method without creating an object. If virtual static methods were allowed, they would have served the purpose.
The only alternative that I can think of is to declare the function func() in all the Derived classes in the header file and remove it from the Base class. Is there any alternative method to do it? So that the declaration is only once in the Base class and all the Derived classes only have to define them, not redeclare?
Calling a virtual function without an object is a contrasense,
since the resolution depends on the type of the object.
are cases where you might need to call the same function
dependant on the type of an object, or specifying the class
explicitly, without an object. This is easily handled by using
two functions, one static, and one virtual. (Typically, the
virtual one will just forward to the static.)
EDIT:
A simple example (from actual code):
#define DECLARE_CLASS_NAME(className) \
static char className() { return STRINGIZE(className); } \
virtual char* getClassName() { return className(); }
class Base
{
public:
DECLARE_CLASS_NAME(Base);
// ...
};
class Derived : public Base
{
public:
DECLARE_CLASS_NAME(Derived);
// ...
};
and so on, in all of the derived classes. This was used to
obtain the type names for serialization, for example:
std::string typeName = pObj->getClassName();
and also as a primitive RTTI (this was about 20 years ago):
if ( pObj->getClassName() == Derived::className() ) ...
(We had established the rule that the only way you could obtain
the name of a class was by using one of these functions. That
effectively internalized the names of the classes, and allowed
simple pointer comparisons to work. On the systems we were
working on then, this was important.)
You can do that a bit hacky =)
//header file
template<class T>
struct base_t
{
static void do_smth();
};
struct derived1_t : base_t<derived1_t>
{
};
struct derived2_t : base_t<derived2_t>
{
};
//cpp file
void base_t<derived1_t>::do_smth() // `note base_t<derived1_t>::` instead of `derived1_t::`
{
std::cout << "aaa" << std::endl;
}
PS: very strange that you do not want to declare this function in derived classes, because when you use virtual functions you should declare them in derived class
One possibility is to only define them in the derived classes:
struct Base
{
// nothing
};
struct Derived1 : public Base
{
static void func() { /*...*/ }
};
struct Derived2 : public Base
{
static void func() { /*...*/ }
};
This allows you to call:
Derived1::foo();
Derived2::foo();
Calling it for the base type and expecting the compiler to figure out which subtype you mean cannot work:
// How will the compiler know to choose
// between Derived1:: func or Derived2:: func ?
Base::func();
You might want to look at CRTP or type-traits for alternative approaches.

CRTP Dispatch in C++11

Say I have the following code:
template <class Derived>
class Base {
public:
virtual void foo_impl() = 0;
void foo() {
static_cast<Derived*>(this)->foo_impl(); //A
(*static_cast<Derived*>(this)).foo_impl(); //B
}
};
class Derived : public Base<Derived> {
private:
void foo_impl() {
bar();
}
};
A few questions:
Will line A generate a virtual function call? Although the majority of what I can find on the internet recommends doing things this way, to me I don't see how the compiler can do static dispatch considering that a pointer to Derived could still actually point to an object of type Derived2 where Derived2 : public Derived.
Does line B fix the issue I brought up in my previous point (if applicable)? It seems like it would, considering that now the call is not on a pointer any more and thus using *. would avoid a virtual function call. But if the compiler treats the dereferenced cast as a reference type, it could still generate a virtual function call... in that case, what is the workaround?
Does adding the C++11 final keyword to foo_impl() change how the compiler would act in either (or any other relevant) case?
Will line A generate a virtual function call?
Yes. foo_impl() is virtual and Derived overrides it. Even though foo_impl() in Derived is not explicitly tagged as virtual, it is in the base class, and this is enough to make it a virtual function.
Does line B fix the issue I brought up in my previous point (if applicable)?
No. It does not matter if the call is on a pointer or on a reference: the compiler still won't know whether you are invoking the function foo_impl() on an instance of a class that derives from Derived, or on a direct instance of Derived. Thus, the call is performed through a vtable.
To see what I mean:
#include <iostream>
using namespace std;
template <class Derived>
class Base {
public:
virtual void foo_impl() = 0;
void foo() {
static_cast<Derived*>(this)->foo_impl();
(*static_cast<Derived*>(this)).foo_impl();
}
};
class Derived : public Base<Derived> {
public:
void foo_impl() {
cout << "Derived::foo_impl()" << endl;
}
};
class MoreDerived : public Derived {
public:
void foo_impl() {
cout << "MoreDerived::foo_impl()" << endl;
}
};
int main()
{
MoreDerived d;
d.foo(); // Will output "MoreDerived::foo_impl()" twice
}
Finally:
Does adding the C++11 final keyword to foo_impl() change how the compiler would act in either (or any other relevant) case?
In theory, yes. The final keyword would make it impossible to override that function in subclasses of Derived. Thus, when performing a function call to foo_impl() through a pointer to Derived, the compiler could resolve the call statically. However, to the best of my knowledge, compilers are not required to do so by the C++ Standard.
CONCLUSION:
In any case, I believe what you actually want to do is not to declare the foo_impl() function at all in the base class. This is normally the case when you use the CRTP. Additionally, you will have to declare class Base<Derived> a friend of Derived if you want it to access Derived's private function foo_impl(). Otherwise, you can make foo_impl() public.
The common idiom for the CRTP does not involve declaring the pure virtual functions in the base. As you mention in one of the comments, that means that the compiler will not enforce the definition of the member in the derived type (other than through use, if there is any use of foo in the base, that requires the presence of foo_impl in the derived type).
While I would stick to the common idiom and not define the pure virtual function in the base, but, if you really feel you need to do it, you can disable dynamic dispatch by adding extra qualification:
template <class Derived>
class Base {
public:
virtual void foo_impl() = 0;
void foo() {
static_cast<Derived*>(this)->Derived::foo_impl();
// ^^^^^^^^^
}
};
The use of the extra qualification Derived:: disables dynamic dispatch, and that call will be statically resolved to Derived::foo_impl. Note that this comes will all of the usual caveats: you have a class with a virtual function and paying the cost of the virtual pointer per object, but you cannot override that virtual function in a most derived type, as the use in the CRTP base is blocking dynamic dispatch...
The extra verbiage in lines A and B have absolutely no effect on
the generated code. I don't know who recommends this (I've never seen
it), but in practice, the only time it might have an effect is
if the function isn't virtual. Just write foo_impl(), and be
done with it.
There is a means of avoiding the virtual function call if the
compiler knows the derived type. I've seen it used for
vector-like classes (where there are different implementations,
e.g. normal, sparse, etc. of the vector):
template <typename T>
class Base
{
private:
virtual T& getValue( int index ) = 0;
public:
T& operator[]( int index ) { return getValue( index ); }
};
template <typename T>
class Derived : public Base<T>
{
private:
virtual T& getValue( int index )
{
return operator[]( index );
}
public:
T& operator[]( index )
{
// find element and return it.
}
};
The idea here is that you normally only work through references
to the base class, but if performance becomes an issue, because
you're using [] in a tight loop, you can dynamic_cast to the
derived class before the loop, and use [] on the derived
class.