duct typing and interface in C++

A

Alain Ketterlin

Marcel Müller said:
Well that is not true in all cases. E.g. the following code will call
a non-existent function and abort at runtime.

[snip example with a call to a pure virtual in a ctor]

This explicitly prohibited by the language definition, so you get what
you deserve (a bit like the OP casting from one type to the other). BTW,
the message at runtime is not "no such function", it is "pure virtual
function called". Note also that if you give a body to the virtual
function in the base class, the call will succeed and execute that body.

-- Alain.
 
G

Goran

NOTE: if some (all?) of you understand Qt, this is my precise problem (Qtis
not the subject of this group, that's why I explain that only now): I define
a QWidget w1, which can include a QWidget w2 that must implement some
methods to be used (say: setText, readText). But if w2 is not given, w1
creates a default w2. w2 is a member of w1, in Python no type is needed for
w2, it must only provide setText and readText. But in C++, I must give a
type to w2 in the definition of w1. I could declare w1 as a template for w2.
But I could also make mandatory to have w2 to derive from an interface
(abstract class) containing setText and readText as pure virtual method; in
this case, as w2 will already derive from some Qt class, we have multiple
inheritance.
Do you understand my problem?

This situation is not specific to Qt. If I were you, I'd do the usual
(or so I think) interface approach:

interface.h
struct IHasText
{
virtual void setText(const QString&) = 0;
virtual QString getText() = 0;
};

factory.h
extern IHasText* createHasText(params);

widget2.h
class Widget2 : public QSomething, IHasText
{
// Implement get/setText here
};

Widget1.h
struct IHasText;
class Widget1
{
IHasText* textProvider_;
};

widget1.cpp
#include "widget.h"
#include "interface.h"
#include "factory.h"
// Implementation of Widget1. E.g.
Widget1::Widget1() : textProvider_(NULL)
{
textProvider_ = createTextProvider(params);
}

(Or something to that extent).

Goran.
 
G

Goran

Well that is not true in all cases. E.g. the following code will call a
non-existent function and abort at runtime.

#include <stdio.h>

class A
{public:
   virtual void foo() = 0;
   A() { bar(); }
  private:
   void bar() { foo(); }

};

class B : public A
{public:
   virtual void foo() { puts("B::foo"); }

};

int main()
{ B b;
   return 0;

}

Hmmm... Original post says "This means that a call like o.quack() in C+
+ will never crash at runtime". It looks implied that there's an
object instance to call a method on (o.quack()). You don't really have
that "o" ;-).

Goran.
 
T

TP

Stuart said:
I think the template based approach should do:

template<class t_ClassTypeOfW2 = DefaultClassForW2>
class MyWidget : public QWidget
{
private:
t_ClassTypeOfW2 w2;

void foo ()
{
w2.SetText ("foo");
}
};

Now you can put any class into t_ClassTypeOfW2 as long as it has a
SetText method (no interfaces needed). However, if you would like to
determine the type of w2 at run-time (or change it), you'll have to
resort to the interface based solution.

Regards,
Stuart

Thanks for your answer. At first sight templating seems to me easier than
multiple inheritance (I have read about multiple inheritance this evening,
there is some subtleties, sometimes).
Below is my solution, in the case of the "duck example" of this post,
inspired from your answer and the one of Nobody.
I have to read further concerning what a proxy is, because below I use this
denomination without really mastering it!
I fact, I realize only now that what I needed is *static* duck typing. So
templating (parametric polymorphism) is the easier solution, it seems.

1/ The version with interface:
==============================

#include <iostream>

class InterfaceDuck
{
public:
virtual void Quack() = 0;
};

class Daffy
{
public:
void Quack()
{
std::cout << "coin coin, I'm Daffy" << std::endl;
}
};

class Donald
{
public:
void Quack()
{
std::cout << "coin coin, I'm Donald" << std::endl;
}
};

template <class T>
class ProxyDuck : public InterfaceDuck
{
public:
T * ref;
ProxyDuck(T * ref) : ref(ref) {}
void Quack() { ref->Quack(); }
};

int main( void )
{
Daffy * dada = new Daffy;
Donald * dodo = new Donald;
ProxyDuck<Daffy> * d = new ProxyDuck<Daffy> ( dada );
ProxyDuck<Donald> * e = new ProxyDuck<Donald> ( dodo );

std::cout << "Daffy is going to quack" << std::endl;
d->Quack();
std::cout << "Donald is going to quack" << std::endl;
e->Quack();

delete d;
delete e;

return 0;
}

2/ The version without interface:
=================================

#include <iostream>

class Daffy
{
public:
void Quack()
{
std::cout << "coin coin, I'm Daffy" << std::endl;
}
};

class Donald
{
public:
void Quack()
{
std::cout << "coin coin, I'm Donald" << std::endl;
}
};

template <class T>
class ProxyDuck
{
public:
T * ref;
ProxyDuck(T * ref) : ref(ref) {}
void Quack() { ref->Quack(); }
};

int main( void )
{
Daffy * dada = new Daffy;
Donald * dodo = new Donald;
ProxyDuck<Daffy> * d = new ProxyDuck<Daffy> ( dada );
ProxyDuck<Donald> * e = new ProxyDuck<Donald> ( dodo );

std::cout << "Daffy is going to quack" << std::endl;
d->Quack();
std::cout << "Donald is going to quack" << std::endl;
e->Quack();

delete d;
delete e;

return 0;
}
 
J

James Kanze

In fact, I would like to have duck typing exactly as in
Python: in Python there is no need to have an inheritance
relation between the interface and the class Daffy. In my
previous post, I pointed to an example with no such
inheritance relation:

I would like to have a construction where the following
affectation is possible:
InterfaceDuck * d = new Daffy;
without inheritance relation between InterfaceDuck and Daffy.
The fact that Daffy has a method Quack() as InterfaceDuck
should be enough to allow that.
But perhaps there is no means to do that in C++?

There isn't. Python and C++ are designed to fulfill different
roles. Duck typing would make C++ inappropriate for many of the
roles it now fills. Duck typing means, for example, only
finding out about errors at runtime. No big deal in a small
program, written in a language without a compiler, in an
interactive development environment, and where robustness isn't
paramount. Not having duck typing means having to go back and
add the proper base classes every time you extend a class to
support a new protocol. Not appropriate in an experimental and
highly dynamic environment, and overkill (and a lot of extra
work) in very small, frequently changing programs.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top