2

I have developed the following code in an attempt to implement non-virtual polymorphism:

#include <functional>
#include <iostream>
namespace{
    using std::function;
    class base {
    protected:
        using signiture =void(void);
        using func_t = function<signiture>;
        ~base(){}
    public:
        func_t bar;//std::function object to a function of type "signature"
    };
}
template <typename implementation>
class foo:public base {
public:
    foo(implementation* instance){
        bar = func_t(std::bind(&implementation::bar_implementation,instance));
//binds a function of name "bar_implementation" from class implementation to the std::function object
//binds to object "instance"
    }
};
typedef base foo_base;

class testcase:public foo<testcase> {
public:
    friend class foo;//allows implementations to be protected or private
    testcase():foo(this){}//sends instance to the constructor of the base class in order to enable binding
protected:
    void bar_implementation(void){
        std::cout<<"Hello"<<std::endl;
    }
};
class testcase2:public foo<testcase2> {
public:
    friend class foo;//allows implementations to be protected or private
    testcase2():foo(this){}
protected:
    void bar_implementation(void){
        std::cout<<"World!"<<std::endl;
    }
};


int main(int argc, const char * argv[]) {
    testcase t;
    testcase2 t2;

    foo_base* b = &t;
    foo_base* b2 = &t2;
    b->bar();
    b2->bar();
    return 0;
}

In reality this code is spread out over a few files...

I would like to know if anything in my code can be considered bad-practice,undefined behavior or otherwise undesirable in some manor? A Live Example

Any thoughts on this pattern as a replacement for virtual inheritance and the design are appreciated.

Let me know if i can clarify anything.

EDIT: I am asking this question as an attempt to determine if there are any reasons why a design like this would be a suitable way to implement non virtual polymorphism and if it is not, why is that?

Alex Zywicki
  • 2,263
  • 1
  • 19
  • 34
  • 4
    Question: Is this code really *not* virtual table polymorphism, or are you just rolling your own? – BlamKiwi Jan 22 '15 at 01:03
  • 5
    Considering that `std::function` uses virtual functions under the hood (to erase the type), I fail to see what this is supposed to accomplish. – T.C. Jan 22 '15 at 01:07
  • 8
    `base::bar` is, for most practical purposes, a single-entry vtable (only more expensive to call through). What again is the point of the exercise? – Igor Tandetnik Jan 22 '15 at 01:10
  • @IgorTandetnik I am asking this question as an attempt to determine if there are any reasons why a design like this would be a suitable way to implement non virtual polymorphism and if it is not, why is that? – Alex Zywicki Jan 22 '15 at 01:14
  • 4
    It looks like you are going out of your way to implement something that the language itself already implements only the language probably does it a lot more efficiently and a lot more safely. – Galik Jan 22 '15 at 01:16
  • 1
    @AlexZywicki I believe studying languages that don't use VTables and why would be more productive than trying to implement your own and asking others why. – BlamKiwi Jan 22 '15 at 01:17
  • 5
    I think part of the problem is this doesn't look like a "non-virtual" something. It looks looks like a manual implementation of a virtual function call system. – Galik Jan 22 '15 at 01:23
  • 1
    It seems to me that 'non-virtual polymorphism' is nothing but a contradiction in terms in this context. What it really refers to is method *overloading.* – user207421 Jan 22 '15 at 01:26
  • 1
    When I wrote the code my intent was to be able to implement a design that would allow me to reap the benefits of polymorphism and method overloading without having to go through the c++ v-table system because in many cases it can be slower to do things virtually. But based on your comments I have come to understand that I have essentially re-invented the wheel here because 1)`std::function` uses virtuality internally and 2) I have created in effect a limited v-table. I was just interested in getting some opinions on the code to determine if I had created a feasible solution or not. – Alex Zywicki Jan 22 '15 at 01:34
  • 2
    It isn't slower to do things virtually if you include the decision-making. Leaving that out, and just compare non-virtual method calls to virtual method calls alone, isn't valid. You need to compare non-virtual method calls *plus the required decision-making* to virtual method calls. When you do that, virtual functions come out equal or ahead, and easier to code with too. – user207421 Jan 22 '15 at 01:39
  • if you'd like to implement non-virtual, static polymorphism, then take a look at the curiously recurring template pattern (CRTP). http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern – plasmacel Jan 22 '15 at 10:39
  • @plasmacel I know the pattern, this code is slightly based off of the idea, but in stead of casting to the child class when making a function call I am binding the std.::function object in the base to the implementation in the child. this in theory allows me to have a single base class which I can store in some form of generic container. That is the main issue, with CRTP i cannot have a common non templated base class can i? – Alex Zywicki Jan 26 '15 at 02:04
  • 1
    No you can not. If a function takes the CRTP base class as an argument, you need to template that function. In practice it's not a problem, thats why templates exists. Keep in mind that std::bind and std::function solution will be slower than CRTP, which will be inlined when optimization turned on. http://stackoverflow.com/questions/5057382/what-is-the-performance-overhead-of-stdfunction – plasmacel Jan 26 '15 at 13:46

1 Answers1

1

Your code is an interesting approach. It's a nice proof of concept but it has a major flaw: it doesn't manage inheritance consistently !

The problem : class inheritance

Suppose I want to create a class testcase22 which inherits from testcase2, but has its own implementation of bar().

Alternative 1: if I define it naively by inheriting from testcase2, it will use the bar_implementation of testcase2:

    class testcase22:public testcase2  {
    public:
        testcase22() {}   // naive contructor
    protected:
        void bar_implementation(void){    // will not be used
            std::cout<<"Great!"<<std::endl;
        }
    };

Alternative 2: If I try to use your constructor pattern, it won't work because of a compiling error. Because the type deduction will use foo<testcase2>, which is not a direct base class of testcase22 and can hence not be used in the mem-initializer list:

    class testcase22:public testcase2  {
    public:
        friend class foo;//allows implementations to be protected or private
        testcase22():foo(this){}   // !!!!! causes compile error
    protected:
        void bar_implementation(void){
            std::cout<<"Great!"<<std::endl;
        }
    };

Alternative 3: if I'd use foo explicitly, it would not work because foo os not either a valid base type initializer.

Alternative 4: if I'd try to use multiple inheritance, I'd be confronted to ambiguous base class

    class testcase22:public testcase2, public foo<testcase22> {
    public:
        friend class foo;//allows implementations to be protected or private
        testcase22():foo(this){}
    protected:
        void bar_implementation(void){
            std::cout<<"Great!"<<std::endl;
        }
    };

This could be solved by defining foo inheriting virtually from base:

    class foo:public virtual base { ... };

Then it would compile, but it still would use the bar_implementation of testcase2 instead of that from testcase22. By the way, even if it would have worked, the virtual base would prevent possibility of using multiple inheritance with your class family.

Conclusion

Your nice construct works, but only with a single level of simple inheritance.

This is a major constraint. Especially when considering that the benefit of polymorphism is to manage natural hierarchies making best use of the inheritance relationships.

Your pattern is also relatively complex to use in comparison with easy to use virtual functions. What will your code look like with several polymorphic functions, some of them even overloaded ?

The goals you intend to achieve with your pattern is not clear, but honestly, I wouldn't go for this approach for real life projects that have to be maintained over several years. But this is my own subjective opinion of course.

Community
  • 1
  • 1
Christophe
  • 68,716
  • 7
  • 72
  • 138
  • This was just a thought experiment so its no big deal if it didn't work. You are correct, the only way that you could make multiple inheritance work is to write the testcase2 class as a CRTP style template and pass the testcase22 typename all the way to foo as well as pass a pointer to testcase22 aka `this` and have the base bind to it. it's not a good way to handle things i know – Alex Zywicki Jan 27 '15 at 04:07