Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C++ (http://www.velocityreviews.com/forums/f39-c.html)
-   -   What's polymorphic in CRTP (http://www.velocityreviews.com/forums/t957518-whats-polymorphic-in-crtp.html)

Jarek Blakarz 02-11-2013 03:40 PM

What's polymorphic in CRTP
 
Hi

I understand what is CRTP. What I don't understand is why CRTP is called a
static polymorphism or rather polymorphism in particular.

I think that it is "static" since the function call is resolved at compile
time, right ?

Assuming that I'm right about "static", plese explain me based on the following
example why it is "polymorphic".

thanks for clarification.



template <class Derived> struct Base {
void interface() { static_cast<Derived*>(this)->implementation(); }
};

struct Derived1 : Base<Derived1> {
void implementation() { }
};

struct Derived2 : Base<Derived2> {
void implementation() { }
};

Derived1 *d1 = new Derived1;
Derived2 *d2 = new Derived2;

d1->interface();
d2->interface();

Stuart 02-11-2013 04:25 PM

Re: What's polymorphic in CRTP
 
On 02/11/13, Jarek Blakarz wrote:
> Hi
>
> I understand what is CRTP. What I don't understand is why CRTP is called a
> static polymorphism or rather polymorphism in particular.


Never heard of this though I have used CRTP lots of times. Most
textbooks make a difference between static and dynamic polymorphism with
regard to whether the polymorphic behaviour is resolved at compile time
or run-time. The classic example for static polymorphism is function
overloading. Although, the term may also be applied to CRTP, I guess.

> I think that it is "static" since the function call is resolved at compile
> time, right ?


I'd say right.

> Assuming that I'm right about "static", plese explain me based on the following
> example why it is "polymorphic".
>
> thanks for clarification.
>
>
>
> template <class Derived> struct Base {
> void interface() { static_cast<Derived*>(this)->implementation(); }


At this place the writer of this code cannot tell which implementation
of the invoked member function "implementation" will be called, so one
could say that the invokation of the "implementation" method on the
"this" pointer is polymorphic behaviour.

I don't like the term "static polymorphism" very much. In my opinion
"polymorphism" and "static" contradict each other. But apparently most
scientist from "applied computer science" (another contradiction?) think
otherwise.

> };
>
> struct Derived1 : Base<Derived1> {
> void implementation() { }
> };
>
> struct Derived2 : Base<Derived2> {
> void implementation() { }
> };
>
> Derived1 *d1 = new Derived1;
> Derived2 *d2 = new Derived2;
>
> d1->interface();
> d2->interface();
>


Regards,
Stuart

Öö Tiib 02-11-2013 04:38 PM

Re: What's polymorphic in CRTP
 
On Monday, 11 February 2013 17:40:04 UTC+2, Jarek Blakarz wrote:
> Hi
>
> I understand what is CRTP. What I don't understand is why CRTP is called a
> static polymorphism or rather polymorphism in particular.


It is not called static polymorphism. It is common technique in C++ to achieve
static polymorphism.

> I think that it is "static" since the function call is resolved at compile
> time, right ?


Yes. You are correct. Exactly like there are arrays with static size
(std::array<T,N>) and dynamic size (std::vector<T>). Static size means lost
flexibility (that is maybe not needed) and won efficiency (that is always
great to have).

> Assuming that I'm right about "static", plese explain me based on the
> following example why it is "polymorphic".


> template <class Derived> struct Base {
> void interface() { static_cast<Derived*>(this)->implementation(); }


This may or not be bare-bone interface. This is basic part of implementation
that calls possibly "statically overriden" member function from derived class.
You can even provide default implementation here:

void implementation() { }

> };
>
> struct Derived1 : Base<Derived1> {
> void implementation() { }
> };
>
> struct Derived2 : Base<Derived2> {
> void implementation() { }
> };


Lets take you have default and also such Derived3 here:

struct Derived3 : Base<Derived3> {
};


> Derived1 *d1 = new Derived1;
> Derived2 *d2 = new Derived2;
> d1->interface();
> d2->interface();


Your example leaks memory and feels like Java with its tons of news at
each corner. C++11 just forgot to add 'std::make_unique<T>()', if that
was in language then need to write 'new' or 'delete' in C++ code was
close to none.

Derived1 d1;
Derived2 d2;
Derived3 d3;
d1.interface();
d2.interface();
d3.interface();

It is polymorphism. All 3 calls may do different things. All 3 calls have
part (possibly everything) of what they do inherited from Base, and part
(possibly nothing) overriden. All 3 calls have exactly same common user
interface.

It is subtly less flexible and more efficient than virtual call ... so
better *you* explain ... what is your problem of calling it polymorphism?

Jarek Blakarz 02-12-2013 03:55 PM

Re: What's polymorphic in CRTP
 
On Monday, February 11, 2013 5:38:03 PM UTC+1, Öö Tiib wrote:
> On Monday, 11 February 2013 17:40:04 UTC+2, Jarek Blakarz wrote:
>
> > Hi

>
> >

>
> > I understand what is CRTP. What I don't understand is why CRTP is called a

>
> > static polymorphism or rather polymorphism in particular.

>
>
>
> It is not called static polymorphism. It is common technique in C++ to achieve
>
> static polymorphism.
>
>
>
> > I think that it is "static" since the function call is resolved at compile

>
> > time, right ?

>
>
>
> Yes. You are correct. Exactly like there are arrays with static size
>
> (std::array<T,N>) and dynamic size (std::vector<T>). Static size means lost
>
> flexibility (that is maybe not needed) and won efficiency (that is always
>
> great to have).
>
>
>
> > Assuming that I'm right about "static", plese explain me based on the

>
> > following example why it is "polymorphic".

>
>
>
> > template <class Derived> struct Base {

>
> > void interface() { static_cast<Derived*>(this)->implementation(); }

>
>
>
> This may or not be bare-bone interface. This is basic part of implementation
>
> that calls possibly "statically overriden" member function from derived class.
>
> You can even provide default implementation here:
>
>
>
> void implementation() { }
>
>
>
> > };

>
> >

>
> > struct Derived1 : Base<Derived1> {

>
> > void implementation() { }

>
> > };

>
> >

>
> > struct Derived2 : Base<Derived2> {

>
> > void implementation() { }

>
> > };

>
>
>
> Lets take you have default and also such Derived3 here:
>
>
>
> struct Derived3 : Base<Derived3> {
>
> };
>
>
>
>
>
> > Derived1 *d1 = new Derived1;

>
> > Derived2 *d2 = new Derived2;

>
> > d1->interface();

>
> > d2->interface();

>
>
>
> Your example leaks memory and feels like Java with its tons of news at
>
> each corner. C++11 just forgot to add 'std::make_unique<T>()', if that
>
> was in language then need to write 'new' or 'delete' in C++ code was
>
> close to none.
>
>
>
> Derived1 d1;
>
> Derived2 d2;
>
> Derived3 d3;
>
> d1.interface();
>
> d2.interface();
>
> d3.interface();
>
>
>
> It is polymorphism. All 3 calls may do different things. All 3 calls have
>
> part (possibly everything) of what they do inherited from Base, and part
>
> (possibly nothing) overriden. All 3 calls have exactly same common user
>
> interface.
>
>
>
> It is subtly less flexible and more efficient than virtual call ... so
>
> better *you* explain ... what is your problem of calling it polymorphism?


Thanks for explanation to everyone.
My goal was just to understand why it is called polymorphism.
Earlier I only suspected why. Now I think I got it.

Cholo Lennon 02-13-2013 07:13 PM

Re: What's polymorphic in CRTP
 
On 12/02/2013 12:55, Jarek Blakarz wrote:

>
> Thanks for explanation to everyone.
> My goal was just to understand why it is called polymorphism.
> Earlier I only suspected why. Now I think I got it.
>


If you are not afraid of Microsoft/Windows/COM you can take a look to
Microsoft ATL library (or its cousin WTL, a tiny header-only library
http://wtl.sourceforge.net/) in order to view an extensive usage of CRTP.

Regards

--
Cholo Lennon
Bs.As.
ARG

Jarek Blakarz 02-15-2013 03:01 PM

Re: What's polymorphic in CRTP
 
Thanks for the reply to all of you.
I spent some time looking at Windows examples but it seems to complex to me at
the beginning.
Could you please give me a simple example of CRTP as a replacement for dynamic
polymorphism. In case of dynamic polymorphism it seems quite obvious to me why
it is powerful. In case of CRTP I still don't feel how it can replace dynamic
polymorphism.

In case of dynamic polymorphism I can refer to the derived classes using
exactly the same interface e.g:

void fun ( Base &base )
{
base.makeSound(); // exactly the same interface for distinct derived classes
}

Unfortunately I cannot apply the same logic to CRTP static polymorphism.
In my initial example above the interface is not "exactly" the same. It is
only "similar". It differs with object name. In case of dynamic polymorphism
whenever I inherit from the base class the interface remains the same. In case
of CRTP static polymorphism whenever I inherit from the base class the
interface changes.

Thanks for the explanation.

Öö Tiib 02-15-2013 04:04 PM

Re: What's polymorphic in CRTP
 
On Friday, 15 February 2013 17:01:53 UTC+2, Jarek Blakarz wrote:
> Thanks for the reply to all of you.
> I spent some time looking at Windows examples but it seems to complex to me at
> the beginning.


WTL (static polymorphism) was made to be alternative GUI toolkit to MFC (deep
dynamic polymorphism). It sort of works so it can replace over-used dynamic
polymorphism.

> Could you please give me a simple example of CRTP as a replacement for dynamic
> polymorphism. In case of dynamic polymorphism it seems quite obvious to me why
> it is powerful. In case of CRTP I still don't feel how it can replace dynamic
> polymorphism.


Yes, whole GUI toolkit is indeed not a simple example but that is it. You want low
level techniques how to convert one to other but there are no such things. There
are real, high-level goals (like GUI toolkit) that can be achieved using one way or
other. CRTP is more efficient than virtual inheritance but it has its limitations too.

> In case of dynamic polymorphism I can refer to the derived classes using
> exactly the same interface e.g:
>
> void fun ( Base &base )
> {
> base.makeSound(); // exactly the same interface for distinct derived classes
> }


What is so hard about it?

template<class T>
void fun( T& t )
{
t.makeSound(); // works for all classes with such member
}

> Unfortunately I cannot apply the same logic to CRTP static polymorphism.
> In my initial example above the interface is not "exactly" the same. It is
> only "similar". It differs with object name. In case of dynamic polymorphism
> whenever I inherit from the base class the interface remains the same. In case
> of CRTP static polymorphism whenever I inherit from the base class the
> interface changes.


Template is more flexible since it does not require you to derive from same base.
Just be "similar" (your word) and you *have* same interface for a template.
If you require exact class in interface then that is what is needed.

Can you explain why you require exact class? There are only limited cases,
like when you want to use exactly same pointer to point to one or other.
That is where you need dynamic polymorphism. Achieve your goal (GUI toolkit)
without having such undetermined pointers in code and CRTP works fine.


Cholo Lennon 02-15-2013 04:18 PM

Re: What's polymorphic in CRTP
 
On 02/15/2013 12:01 PM, Jarek Blakarz wrote:
> Thanks for the reply to all of you.
> I spent some time looking at Windows examples but it seems to complex to me at
> the beginning.
> Could you please give me a simple example of CRTP as a replacement for dynamic
> polymorphism. In case of dynamic polymorphism it seems quite obvious to me why
> it is powerful. In case of CRTP I still don't feel how it can replace dynamic
> polymorphism.
>
> In case of dynamic polymorphism I can refer to the derived classes using
> exactly the same interface e.g:
>
> void fun ( Base &base )
> {
> base.makeSound(); // exactly the same interface for distinct derived classes
> }
>
> Unfortunately I cannot apply the same logic to CRTP static polymorphism.
> In my initial example above the interface is not "exactly" the same. It is
> only "similar". It differs with object name. In case of dynamic polymorphism
> whenever I inherit from the base class the interface remains the same. In case
> of CRTP static polymorphism whenever I inherit from the base class the
> interface changes.
>
> Thanks for the explanation.
>


How about this?


#include <iostream>

template<class T>
class Base {

public:
void callDynamic()
{
onDynamic();
}

void callStatic()
{
T* pThis = static_cast<T*>(this);
pThis->onStatic();
}


virtual void onDynamic()
{
std::cout << "Base::onDynamic" << std::endl;
}

void onStatic()
{
std::cout << "Base::onStatic" << std::endl;
}

};


class Derived: public Base<Derived> {

public:

virtual void onDynamic()
{
std::cout << "Derived::onDynamic" << std::endl;
}

// "pseudo virtual" function :-)
void onStatic()
{
std::cout << "Derived::onStatic" << std::endl;
}

};


int main(int, char**)
{
Derived derived;
derived.callDynamic();
derived.callStatic();
}


Also, try commenting out functions in Derived class to see what happens

Regards


--
Cholo Lennon
Bs.As.
ARG


Öö Tiib 02-15-2013 04:33 PM

Re: What's polymorphic in CRTP
 
On Friday, 15 February 2013 18:18:47 UTC+2, Cholo Lennon wrote:
> How about this?


It is example that works but does not achieve much else but inefficiency.
;-)

> #include <iostream>
>
> template<class T>
> class Base {


Note that T is meant to be derived class.
So you can not use Base<Derived>* as dynamically polymorphic interface
pointer for several different "Derived"s.

> public:
> void callDynamic()
> {
> onDynamic();
> }
>
> void callStatic()
> {
> T* pThis = static_cast<T*>(this);
> pThis->onStatic();
> }
>
> virtual void onDynamic()
> {
> std::cout << "Base::onDynamic" << std::endl;
> }
>
> void onStatic()
> {
> std::cout << "Base::onStatic" << std::endl;
> }
>
> };
>
>
> class Derived: public Base<Derived> {
>
> public:
>
> virtual void onDynamic()
> {
> std::cout << "Derived::onDynamic" << std::endl;
> }
>
> // "pseudo virtual" function :-)
> void onStatic()
> {
> std::cout << "Derived::onStatic" << std::endl;
> }
> };
>
>
> int main(int, char**)
> {
> Derived derived;
> derived.callDynamic();
> derived.callStatic();
> }
>
>
> Also, try commenting out functions in Derived class to see what happens


Just try making it with Derived1, Derived2 and Derived3 and you see where you
went wrong. Do not mix CRTP with dynamic polymorphism. Use typical
pure abstract interface base and multiple inheritance side by side with
CRTP if you need to mix them.

Cholo Lennon 02-15-2013 04:55 PM

Re: What's polymorphic in CRTP
 
On 02/15/2013 01:33 PM, Öö Tiib wrote:
> On Friday, 15 February 2013 18:18:47 UTC+2, Cholo Lennon wrote:
>> How about this?

>
> It is example that works but does not achieve much else but inefficiency.
> ;-)


Why the example is inefficient? The call to Derived::onStatic is
resolved at compile time.

Also, in order to simplify the code I put the dynamic/static variants in
the same class.

The example shows static polymorphism as is used in ATL (WTL). It was
not intended to be used/interpreted in another way.

>
>> #include <iostream>
>>
>> template<class T>
>> class Base {

>
> Note that T is meant to be derived class.
> So you can not use Base<Derived>* as dynamically polymorphic interface
> pointer for several different "Derived"s.
>
>> public:
>> void callDynamic()
>> {
>> onDynamic();
>> }
>>
>> void callStatic()
>> {
>> T* pThis = static_cast<T*>(this);
>> pThis->onStatic();
>> }
>>
>> virtual void onDynamic()
>> {
>> std::cout << "Base::onDynamic" << std::endl;
>> }
>>
>> void onStatic()
>> {
>> std::cout << "Base::onStatic" << std::endl;
>> }
>>
>> };
>>
>>
>> class Derived: public Base<Derived> {
>>
>> public:
>>
>> virtual void onDynamic()
>> {
>> std::cout << "Derived::onDynamic" << std::endl;
>> }
>>
>> // "pseudo virtual" function :-)
>> void onStatic()
>> {
>> std::cout << "Derived::onStatic" << std::endl;
>> }
>> };
>>
>>
>> int main(int, char**)
>> {
>> Derived derived;
>> derived.callDynamic();
>> derived.callStatic();
>> }
>>
>>
>> Also, try commenting out functions in Derived class to see what happens

>
> Just try making it with Derived1, Derived2 and Derived3 and you see where you
> went wrong. Do not mix CRTP with dynamic polymorphism. Use typical
> pure abstract interface base and multiple inheritance side by side with
> CRTP if you need to mix them.
>



--
Cholo Lennon
Bs.As.
ARG


All times are GMT. The time now is 03:31 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.