Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Combining Static and Dynamic Polymorphism to Create "Hyper Polymorphism"?

By mixing both static and dynamic polymorphism (templates and inheritance) I have come across a strange technique that functions similarly to regular static polymorphism in C++, except the members of the child class are still visible after creating the new object.

Consider the following example:


Base.h:

#include <iostream>

class Base {
public:
    virtual ~Base() {}

    virtual void say_hello() {
        std::cout << "Hello from Base!" << std::endl;
    }
};

Class1.h:

#include "Base.h"
#include <iostream>

class Class1 : public Base {
public:
    virtual void say_hello() {
        std::cout << "Hello from Class1!" << std::endl;
    }

    int x = 1;
};

Class2.h:

#include "Base.h"
#include <iostream>

class Class2 : public Base {
public:
    virtual void say_hello() {
        std::cout << "Hello from Class2!" << std::endl;
    }

    int y = 2;
};

This is where things get interesting...

ClassX.h

template <class T>
class ClassX : public T {
public:
    int z = 3;
};

By implementing classX in such a way that it can dynamically inherit from anything it allows some strange things to occur. See the example below showing it in use.

main.cpp

#include <iostream>
#include "Base.h"
#include "Class1.h"
#include "Class2.h"
#include "ClassX.h"

using namespace std;

int main(int argc, char* argv[]) {

    Base* b = new Base;
    b->say_hello();

    // Regular polymorphism in action
    Base* c1 = new Class1;
    c1->say_hello();         // Aware that this is Class1
    //cout << c1->x << endl; // Doesn't work! Not visible from here

    Base* c2 = new Class2;
    c2->say_hello();         // Aware that this is Class2
    //cout << c2->y << endl; // Doesn't work! Not visible from here

    // Hyper polymorphism!? Not sure what to call this.
    ClassX<Class1> cx1;
    cx1.say_hello();       // Aware that this is Class1
    cout << cx1.x << endl; // The member variable is visible!
    cout << cx1.z << endl; // Also available :)

    ClassX<Class2> cx2;
    cx2.say_hello();       // Aware that this is Class2
    cout << cx2.y << endl; // The member variable is visible!
    cout << cx2.z << endl; // Also available :)

    // ALWAYS delete objects created with "new" or shame on yew.
    delete b;
    delete c1;
    delete c2;
}

What I'm wondering is why have I never seen this technique before? I've never once seen anyone try to inherit from an unknown class using templates like this:

template <class T>
class Name : public T {
    // Implementation
};

Is there a name to this technique, and what are it's uses?

I just gave it a try because knowing the rules of C++ I didn't see a reason why it wouldn't work. Since I can't seem to find a name for it anywhere I'm going to call this technique "Hyper Polymorphism" :)

like image 913
tjwrona1992 Avatar asked May 09 '17 19:05

tjwrona1992


People also ask

How are static and dynamic polymorphism implemented in C++?

Dynamic polymorphism happens at run time and static polymorphism at compile time. Dynamic polymorphism requires typically a pointer indirection at run time (read the post "Demystifying virtual functions, Vtable, and VPTR in C++"), but static polymorphism has no performance costs at run time.

What is polymorphism explain the difference between static and dynamic polymorphism with example?

Definition. Static polymorphism is a type of polymorphism that collects the information to call a method during compile time while dynamic polymorphism is a type of polymorphism that collects information to call a method at run time. Thus, this is the main difference between static and dynamic polymorphism.

What is dynamic polymorphism how virtual and override is runtime or dynamic polymorphism?

Dynamic polymorphism is a process or mechanism in which a call to an overridden method is to resolve at runtime rather than compile-time. It is also known as runtime polymorphism or dynamic method dispatch. We can achieve dynamic polymorphism by using the method overriding.

Why is dynamic polymorphism needed?

Dynamic Polymorphism allows Java to support overriding of methods which is central for run-time polymorphism. It allows a class to specify methods that will be common to all of its derivatives while allowing subclasses to define the specific implementation of some or all of those methods.


2 Answers

EDIT: sorry misunderstood an important part of OPs code. Shame on me. Removed the wrong part of my answer. However, the following still holds...

Imho your comparison isnt fair

Base* c2 = new Class2;
//cout << c2->y << endl; // Doesn't work! Not visible from here

ClassX<Class1> cx1;
cout << cx1.x << endl; // The member variable is visible!

These are two completely different cases. A fair comparison would be

Base* c2 = new Class2;
//cout << c2->y << endl; // Doesn't work! Not visible from here

vs

Base* cx1 = new ClassX<Class1>();
//cout << cx1->x << endl; // Wont work as well !!!

(see here for an example) or

Class2 c2;
cout << c2.y << endl; // Works of course

vs

ClassX<Class1> cx1;
cout << cx1.x << endl; // Works of course as well !!!

That said, this technique might have its applications. For example the case you mentioned in a comment, when you need to add the same functionality to many differnt base classes.

Is there a name to this technique, and what are it's uses?

Afaik there isnt a name for this. The uses are, as others have mentioned in comments, to decorate many different classes with the same functionality.

I have to admit that only after @Amadeus pointed out that half of my answer was wrong, I fully understood the approach in OPs code. Imho it is quite some effort (twice inheriting plus a template) for not too much gain, and maybe thats the reason why it isnt a well known and commonly applied technique. Though it might be useful in some special cases.

like image 125
463035818_is_not_a_number Avatar answered Oct 20 '22 23:10

463035818_is_not_a_number


From reading the comments it looks like this technique is actually considered a "decorator pattern".

It can be used when you need to extend the functionality of multiple existing classes (for example adding a member variable z) when you can't modify the classes directly.

It's more flexible than regular inheritance because you can extend the functionality of many classes by only writing one new class.

Not exactly the same as "hyper polymorphism", but hey, maybe that will be a thing some day. ;)

like image 24
tjwrona1992 Avatar answered Oct 20 '22 23:10

tjwrona1992