C++ idiom for base class abstract methods without dynamic dispatch overhead? - c++

In C++, is there any way to have an "abstract" base class method (i.e., declared and callable from the base class, but implemented in subclasses) without declaring the method as virtual?
This question, of course, only applies to cases where polymorphism isn't needed (pointers/references to base types never used). Consider the following:
#define NO_OPT asm volatile (""); // to prevent some compiler optimization
template<typename DerivedType>
void doSomething(DerivedType& d) { d.foo(); }
namespace test1 {
struct Base {
inline void foo()
{
// ... do common stuff pre-call ...
foo_impl();
// ... do common stuff post-call ...
}
virtual void foo_impl() = 0; // the abstract method
};
struct D1 : public Base { virtual void foo_impl() final { NO_OPT } };
struct D2 : public Base { virtual void foo_impl() final { NO_OPT } };
// Then the usage of D1, D2, ..., DN, could be as follows:
void go() {
D1 d1; doSomething(d1);
D2 d2; doSomething(d2);
for ( long i=0; i < 5000000000; i++ ) {
// this loop takes [9] seconds
doSomething(d2);
}
}
}
Note that polymorphism is not needed in this case, and that there are plenty of optimization opportunities for the compiler.
However, I benchmarked this code in the latest g++ (4.8.2) and clang (3.4) with -O3 optimizations enabled, including link-time (LTO), and it was significantly slower than the following alternative implementation (using templates instead of virtual method):
namespace test2 {
template<typename DerivedType>
struct Base : public DerivedType // inheritance in reverse
{
inline void foo()
{
// ... do common stuff pre-call ...
DerivedType::foo_impl();
// ... do common stuff post-call ...
}
};
struct D1 { void foo_impl() { NO_OPT } };
struct D2 { void foo_impl() { NO_OPT } };
void go() {
Base<D1> d1; doSomething(d1);
Base<D2> d2; doSomething(d2);
for ( long i=0; i < 5000000000; i++ ) {
// this loop takes [3] seconds
doSomething(d2);
}
}
}
g++ and clang were remarkably consistent, each compiling optimized code that took 9 seconds to execute the test1 loop, but only 3 seconds to execute the test2 loop. So even though the test1 logic has no need for dynamic dispatch as all calls should be able to be resolved at compile time, it is still significantly slower.
So to restate my question: When polymorphism isn't needed, Is there a way to achieve this "abstract method" behavior using the convenient straight-forward class inheritance (like in test1), but without the performance penalty of virtual functions (as achieved in test2)?

Why should explicitly invoking runtime support for a situation you don't have and don't want to have be considered straightforward? That'll confuse humans, too. Templates are the perfect tool for this job.
You want a common interface. Given your example template implementation, you don't even need any obvious relation between the types that have it, just that they do have it.
The classic CRTP way is
template<class d>
struct b {
void foo() { bark(); static_cast<d*>(this)->foo_impl(); bite(); }
};
struct d1 : b<d1> { void foo_impl() { fuzzbang("d1"); } };
struct d2 : b<d2> { void foo_impl() { fizzbuzz("d2"); } };
which people will have seen before, it's idiomatic as requested, but your
class m1 { protected: void foo_impl() { f1("1"); } };
class m2 { protected: void foo_impl() { f2("2"); } };
template<class m>
struct i : private m { void foo() { bark(); m::foo_impl(); bite(); } };
has a lot to recommend it too: there's no casting necessary, and the intent is as clear.
I don't think you can legitimately compare optimizer results on code with embedded volatile accesses with results on similar code without them. Try the two implementations in your actual code. Performance for anything you're doing five billion times is almost certain to be dominated by cache effects not instruction count anyway.

If a function has a polymorphic value (a reference or pointer to a polymorphic type), and it calls a virtual function through that variable, the compiler must assume that this could be that class or any class derived from it. And since polymorphism doesn't allow the compiler to know whether there are classes derived from it, it must use a virtual dispatch to call the function.
There is only one way to avoid the use of virtual dispatch on calling a virtual function via a polymorphic value: to call the specific type's function directly, exactly as you did in your case #2.
Where you put this call is up to you. You could put the call into foo, you could have a derived_foo alternate function that people use to call the derived-class version, etc. However you want to do it, you must ultimately call the virtual function in a different way. Which requires using a different codepath.
It is possible that, if provided with a polymorphic variable of a final class, a compiler could optimize all virtual calls into that variable into non-virtual dispatches. However, that is not required behavior by the standard. Each compiler may or may not implement that optimization, so unless it becomes widespread, you can't count on it.
This question seems very much like an XY problem. You're trying to solve some problem, and you settled on a base class with a virtual function, with a derived class that you'll always be using. This problem is best solved via the CRTP, which doesn't use virtual functions at all.

If you do not need dynamic polymorphism then do not use keyword virtual in your code:
#define NO_OPT asm volatile (""); // to prevent some compiler optimization
template<typename T>
void doSomething(T& d) { d.foo(); }
namespace test1
{
struct Base
{
protected:
void prior() {}
void after() {}
};
struct D1
:public Base
{
void foo()
{
prior();
NO_OPT
after();
}
};
struct D2
:public Base
{
void foo()
{
prior();
NO_OPT
after();
}
};
void go() {
D1 d1; doSomething(d1);
D2 d2; doSomething(d2);
for ( long i=0; i < 5000000000; i++ ) {
doSomething(d2);
}
}
}

Related

Optional class members without runtime overhead

I have the following very general problem that I have not found a satisfying solution to yet:
So I want to have two classes A and AData that are basically identical except that the latter has an additional attribute data and each of the classes supports a function foo(), which is different because it depends on the existence of the additional data.
The stupid solution is to copy the entire class and change it slightly, but that leads to code duplication and is hard to maintain. Using std::optional or a pointer lead to additional checks and therefore runtime overhead, right?
My question is whether there is a way to get the same runtime performance as just copying the code without actual code duplication? My current solution is to make AData a derived class and declare it as friend of A and then override the virtual function foo(), but I do not like this approach due to the use of friend.
You can use static polymorphism and curiosly recurring template pattern.
Both A and AData provide foo() but behaviour is class-specfic through doFoo(). Also not using virtual dispatch avoids runtime overhead of vtable lookup.
template <typename TData>
class Abase
{
public:
void foo()
{
static_cast<TData*>(this)->doFoo();
}
};
class A : public Abase<A>
{
friend ABase<A>;
void doFoo() { cout << "A::foo()\n"; }
};
class AData : public Abase<AData>
{
friend Abase<AData>;
int someDataMember;
void doFoo() { cout << "AData::foo()\n"; /*... use someDataMember ... */}
};
Live
Why not use composition:
class A
{
public:
void foo() { /*...*/ }
};
class AData
{
A a;
int someDataMember;
public:
void foo() { /*... use someDataMember ...*/ }
};

static_assert : a certain function in Derive "must" hides Base's class function

I face a strange rare problem that I want to hide a Base class's function B::f1(int).
class B{
public: void f1(int){}
public: void f1(float){}
};
class C : public B{
public: void f1(int){
//static_assert(ASSERT_that_thisFunctionHidParentFunction,"");
//some rare ugly hacky stuff
}
public: void f1(char){
//static_assert(!ASSERT_that_thisFunctionHidParentFunction,"");
}
};
Everything works fine ; I just worry about maintainability.
I wish to make sure that a function C::f1(int) always hides B::f1(int).
If B::f1(int) happen to change signature in the future (e.g. to B::f1(int,int)),
I want some compile error to notify programmers that C::f1(int) should be changed to C::f1(int,int) as well.
In real world, my problematic function f1 doesn't have overload.
But for educational purpose, I wish to know how to solve it if there are overload too. (i.e. optional)
I love a cute solution like ASSERT_that_thisFunctionHidParentFunction in my code comment.
I don't mind MACRO.
My poor solution
I tried to typedef to force compile error, but it doesn't assert-fail in some case (MCVE-coliru), because int is automatically casted to B::f1(float).
class B{
public: void f1(int,int){}
public: void f1(float){}
};
class C : public B{
public: void f1(int){
using XXX=decltype(std::declval<B>().f1(std::declval<int>()));
//static_assert(ASSERT_that_thisFunctionHidParentFunction,"");
}
public: void f1(char){
//static_assert(!ASSERT_that_thisFunctionHidParentFunction,"");
}
};
int main() {
return 0;
}
You could check that the function pointers are different.
With MSVC 2019 and Clang 8 this worked for me, however GCC rejected it as "not a constant expression", so might need something different or a a runtime assert there. Not sure which is right in regards to the standard.
class B {
public:
void f1(int) {}
void f2(int) {}
void f3(int) {}
void f1(float) {}
};
class C : public B {
public:
void f1(int) {}
void f1(char) {}
void f3(int) {}
};
static_assert(&B::f1 != &C::f1); // Won't work because of the overloading, can static_cast to get the overload you want
static_assert(static_cast<void(B:: *)(int)>(&B::f1) != static_cast<void(C:: *)(int)>(&C::f1));
static_assert(static_cast<void(B:: *)(int)>(&B::f2) != static_cast<void(C:: *)(int)>(&C::f2)); // static assertion failed
static_assert(&B::f3 != &C::f3); // passes, no static_cast as not overloaded
Be very careful with hiding a member function in this way, as the base class is public and the method is not virtual. It can easily be cast and then the derived function is not called.
C *c = ...;
B *b = c; // Implicit
b->f1(5); // Calls B::f1, not C::f1
If possible it may be best to make the inheritance protected or private to avoid accidental casting.
The way I understand your question, it seems that you want to make sure that several implementation classes comply with a certain non-virtual concept.
template <typename Candidate>
struct ShipConcept
{
constexpr ShipConcept()
{
using ProtoFoo = void (Candidate::*)(int);
(void)static_cast<ProtoFoo>(&Candidate::foo);
// Other tests ...
}
};
struct Ship_A
: private ShipConcept<Ship_A>
{
Ship_A()
{
}
void foo(int, int);
void foo(float);
void foo(int); // (1)
};
You'll get compile-time error if line (1) isn't there.

Grouping two types together

I use a third party library over which I have no control. It contains 2 classes A and B, which both define a method with the same name:
class A {
public:
...
void my_method ();
};
class B {
public:
...
void my_method ();
};
I want to create a class C that contains a member which is of class A or B. Crucially, I can know only at runtime whether I will need A or B. This class C will only call the method my_method.
If I could modify the code, I would simply make A and B derive from a parent class (interface) that defined my_method. But I can't.
What is the simplest/most elegant way to create this class C? I could of course define C in this way:
class C {
public:
void call_my_method() { if (a) a->my_method() else b->my_method(); }
private:
A* a;
B* b;
But I want to avoid paying the cost of the if statement everytime. It also feels inelegant. Is there a way I can create a super type of class A or B? Or any other solution to this problem?
You may use std::function (not sure it has better performance though), something like:
class C {
public:
void call_my_method() { my_method(); }
void use_a(A* a) { my_method = [=]() { a->my_method() }; }
void use_b(B* b) { my_method = [=]() { b->my_method() }; }
private:
std::function<void()> my_method;
};
No; at some point you need branching. The best you can do is to hoist the branching up/down the call stack†, so that more of your program is encapsulated within the figurative if/else construct and the branch itself need be performed less frequently. Of course then you need to duplicate more of your program's source code, which is not ideal.
The only improvement I'd suggest at this time is a construct such as boost::variant. It basically does what you're already doing, but takes up less memory and doesn't have that layer of indirection (using what's called a tagged union instead). It still needs to branch on access, but until profiling has revealed that this is a big bottleneck (and you'll probably find that branch prediction alleviates much of this risk) I wouldn't go any further with your changes.&ddagger;
† I can never remember which way it goes lol
&ddagger; One such change might be to conditionally initialise a function pointer (or modern std::function), then call the function each time. However, that's a lot of indirection. You should profile, but I'd expect it to be slower and harder on the caches. An OO purist might recommend a polymorphic inheritance tree and virtual dispatch, but that's not going to be of any use to you once you care about performance this much.
How about using inheritance with a virtual function, using a 'base class' (C):
class C
{
public:
virtual void do_method() = 0;
};
class D : public C, private A
{
void do_method() { my_method(); }
};
class E : public C, private B
{
void do_method() { my_method(); }
}
Then this will work:
C * d = new D();
d->do_method();
Suggest to wrap your A and B objects into some helper template TProxy which realizes IProxy interface. Class C (or Consumer) will work with IProxy interface and won't know about type of the object inside Proxy
#include <stdio.h>
struct A {
void func () { printf("A::func\n"); }
};
struct B {
void func () { printf("B::func\n"); }
};
struct IProxy
{
virtual void doFunc() = 0;
virtual ~IProxy() {};
};
template<typename T>
struct TProxy : public IProxy
{
TProxy(T& i_obj) : m_obj(i_obj) { }
virtual void doFunc() override { m_obj.func(); }
private:
T& m_obj;
};
class Consumer
{
public:
Consumer(IProxy& i_proxy) : m_proxy(i_proxy) {}
void Func() { m_proxy.doFunc();}
private:
IProxy& m_proxy;
};
Main:
int main()
{
A a;
TProxy<A> aProxy(a);
B b;
TProxy<B> bProxy(b);
Consumer consumerA{aProxy};
consumerA.Func();
Consumer consumerB{bProxy};
consumerB.Func();
return 0;
}
Output:
A::func
B::func

Templates as an alternative to virtual functions in C++

I have an expensive function defined in a base class, which depends on low level information from its derived classes:
class BaseClass{
...
// Defined in derived class
virtual int low_level(int)=0;
// Expensive function depending on the pure virtual function
void myExpensiveFunction(){
for(...){
for(...){
for(...){
... = low_level(...);
...
}
}
}
}
};
class DerivedClass : public BaseClass{
// A very cheap operation that can be inlined:
inline virtual int low_level(int i){
return a[i];
}
// Calling the base class function
void test(){
myExpensiveFunction();
}
};
If I understand things correctly, the fact that the low-level function is virtual prevents it from being inlined in the code above. Now, I was thinking about a way to get around this and thought of the following solution, where I pass a pointer to the derived class member function as a template parameter:
class BaseClass{
...
// The function is now templated by the derived function:
template<typename D, int (D::*low_level)(int)>
void myExpensiveFunction(){
for(...){
for(...){
for(...){
... = static_cast<D*>(this)->low_level(...);
...
}
}
}
}
};
class DerivedClass : public BaseClass{
// A very cheap operation that can be inlined:
inline int low_level(int i){
return a[i];
}
// Calling the base class function
void test(){
myExpensiveFunction<DerivedClass,&DerivedClass::low_level>();
}
};
Does this strategy make sense? I imagine that the low level operation will be inlined when the expensive base class function is expanded in the derived class.
I tested implementing it and it compiles and works, but I haven't seen any noticeable differences in performance.
Kind regards,
Joel
Passing the function you want to call using a pointer to member to a base class doesn't really improve over using a virtual function. In fact, I would expect it to make the situation worse. An alternative approach is to use a function object with an inline function call operator and call this. The "normal" approach is to kind of invert the class hierarchy and use the Curiously Recurring Template Pattern: the idea is to create a template which will derive from its template argument. The template argument is expected to provide the customization points, e.g. the function low_level.
Depending on the situation, you could also try to avoid inheritance altogether and do something like this instead:
template<typename LL>
class HighLevel {
LL lowLevel;
public:
HighLevel(LL const &ll) : lowLevel(ll) { }
void myExpensiveFunction() {
for(...) {
for(...) {
for(...) {
... = lowLevel.low_level(...);
...
}
}
}
}
};
class LowLevel {
public:
inline int low_level(int i) { // note: not virtual
return a[i];
}
};
Used like:
HighLevel<LowLevel> hl;
hl.myExpensiveFunction();
If you don't want different types of HighLevel<...> objects floating around, you could derive all those from an abstract, non-template class HighLevelBase which exposes a virtual void myExpensiveFunction() = 0 that gets implemented in the template.
Whether or not this makes sense for your situation, I cannot tell without more information, but I find that C++ often offers better tools than inheritance to solve particular problems.

Enforcing correct parameter types in derived virtual function

I'm finding it difficult to describe this problem very concisely, so I've attached the code for a demonstration program.
The general idea is that we want a set of Derived classes that are forced to implement some abstract Foo() function from a Base class. Each of the derived Foo() calls must accept a different parameter as input, but all of the parameters should also be derived from a BaseInput class.
We see two possible solutions so far, neither we're very happy with:
Remove the Foo() function from the base class and reimplement it with the correct input types in each Derived class. This, however, removes the enforcement that it be implemented in the same manner in each derived class.
Do some kind of dynamic cast inside the receiving function to verify that the type received is correct. However, this does not prevent the programmer from making an error and passing the incorrect input data type. We would like the type to be passed to the Foo() function to be compile-time correct.
Is there some sort of pattern that could enforce this kind of behaviour? Is this whole idea breaking some sort of fundamental idea underlying OOP? We'd really like to hear your input on possible solutions outside of what we've come up with.
Thanks so much!
#include <iostream>
// these inputs will be sent to our Foo function below
class BaseInput {};
class Derived1Input : public BaseInput { public: int d1Custom; };
class Derived2Input : public BaseInput { public: float d2Custom; };
class Base
{
public:
virtual void Foo(BaseInput& i) = 0;
};
class Derived1 : public Base
{
public:
// we don't know what type the input is -- do we have to try to cast to what we want
// and see if it works?
virtual void Foo(BaseInput& i) { std::cout << "I don't want to cast this..." << std::endl; }
// prefer something like this, but then it's not overriding the Base implementation
//virtual void Foo(Derived1Input& i) { std::cout << "Derived1 did something with Derived1Input..." << std::endl; }
};
class Derived2 : public Base
{
public:
// we don't know what type the input is -- do we have to try to cast to what we want
// and see if it works?
virtual void Foo(BaseInput& i) { std::cout << "I don't want to cast this..." << std::endl; }
// prefer something like this, but then it's not overriding the Base implementation
//virtual void Foo(Derived2Input& i) { std::cout << "Derived2 did something with Derived2Input..." << std::endl; }
};
int main()
{
Derived1 d1; Derived1Input d1i;
Derived2 d2; Derived2Input d2i;
// set up some dummy data
d1i.d1Custom = 1;
d2i.d2Custom = 1.f;
d1.Foo(d2i); // this compiles, but is a mistake! how can we avoid this?
// Derived1::Foo() should only accept Derived1Input, but then
// we can't declare Foo() in the Base class.
return 0;
}
Since your Derived class is-a Base class, it should never tighten the base contract preconditions: if it has to behave like a Base, it should accept BaseInput allright. This is known as the Liskov Substitution Principle.
Although you can do runtime checking of your argument, you can never achieve a fully type-safe way of doing this: your compiler may be able to match the DerivedInput when it sees a Derived object (static type), but it can not know what subtype is going to be behind a Base object...
The requirements
DerivedX should take a DerivedXInput
DerivedX::Foo should be interface-equal to DerivedY::Foo
contradict: either the Foo methods are implemented in terms of the BaseInput, and thus have identical interfaces in all derived classes, or the DerivedXInput types differ, and they cannot have the same interface.
That's, in my opinion, the problem.
This problem occured to me, too, when writing tightly coupled classes that are handled in a type-unaware framework:
class Fruit {};
class FruitTree {
virtual Fruit* pick() = 0;
};
class FruitEater {
virtual void eat( Fruit* ) = 0;
};
class Banana : public Fruit {};
class BananaTree {
virtual Banana* pick() { return new Banana; }
};
class BananaEater : public FruitEater {
void eat( Fruit* f ){
assert( dynamic_cast<Banana*>(f)!=0 );
delete f;
}
};
And a framework:
struct FruitPipeLine {
FruitTree* tree;
FruitEater* eater;
void cycle(){
eater->eat( tree->pick() );
}
};
Now this proves a design that's too easily broken: there's no part in the design that aligns the trees with the eaters:
FruitPipeLine pipe = { new BananaTree, new LemonEater }; // compiles fine
pipe.cycle(); // crash, probably.
You may improve the cohesion of the design, and remove the need for virtual dispatching, by making it a template:
template<class F> class Tree {
F* pick(); // no implementation
};
template<class F> class Eater {
void eat( F* f ){ delete f; } // default implementation is possible
};
template<class F> PipeLine {
Tree<F> tree;
Eater<F> eater;
void cycle(){ eater.eat( tree.pick() ); }
};
The implementations are really template specializations:
template<> class Tree<Banana> {
Banana* pick(){ return new Banana; }
};
...
PipeLine<Banana> pipe; // can't be wrong
pipe.cycle(); // no typechecking needed.
You might be able to use a variation of the curiously recurring template pattern.
class Base {
public:
// Stuff that don't depend on the input type.
};
template <typename Input>
class Middle : public Base {
public:
virtual void Foo(Input &i) = 0;
};
class Derived1 : public Middle<Derived1Input> {
public:
virtual void Foo(Derived1Input &i) { ... }
};
class Derived2 : public Middle<Derived2Input> {
public:
virtual void Foo(Derived2Input &i) { ... }
};
This is untested, just a shot from the hip!
If you don't mind the dynamic cast, how about this:
Class BaseInput;
class Base
{
public:
void foo(BaseInput & x) { foo_dispatch(x); };
private:
virtual void foo_dispatch(BaseInput &) = 0;
};
template <typename TInput = BaseInput> // default value to enforce nothing
class FooDistpatch : public Base
{
virtual void foo_dispatch(BaseInput & x)
{
foo_impl(dynamic_cast<TInput &>(x));
}
virtual void foo_impl(TInput &) = 0;
};
class Derived1 : public FooDispatch<Der1Input>
{
virtual void foo_impl(Der1Input & x) { /* your implementation here */ }
};
That way, you've built the dynamic type checking into the intermediate class, and your clients only ever derive from FooDispatch<DerivedInput>.
What you are talking about are covariant argument types, and that is quite an uncommon feature in a language, as it breaks your contract: You promised to accept a base_input object because you inherit from base, but you want the compiler to reject all but a small subset of base_inputs...
It is much more common for programming languages to offer the opposite: contra-variant argument types, as the derived type will not only accept everything that it is bound to accept by the contract, but also other types.
At any rate, C++ does not offer contravariance in argument types either, only covariance in the return type.
C++ has a lot of dark areas, so it's hard to say any specific thing is undoable, but going from the dark areas I do know, without a cast, this cannot be done. The virtual function specified in the base class requires the argument type to remain the same in all the children.
I am sure a cast can be used in a non-painful way though, perhaps by giving the base class an Enum 'type' member that is uniquely set by the constructor of each possible child that might possibly inherit it. Foo() can then check that 'type' and determine which type it is before doing anything, and throwing an assertion if it is surprised by something unexpected. It isn't compile time, but it's the closest a compromise I can think of, while still having the benefits of requiring a Foo() be defined.
It's certainly restricted, but you can use/simulate coviarance in constructors parameters.