[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-core-devel
Subject: Re: Proposing the removal of virtual_hooks (or how you can add a
From: Frans Englich <frans.englich () telia ! com>
Date: 2006-03-05 22:18:16
Message-ID: 200603052218.17153.frans.englich () telia ! com
[Download RAW message or body]
On Sunday 05 March 2006 16:50, Thiago Macieira wrote:
> Frans Englich wrote:
> >On Saturday 04 March 2006 11:18, Thiago Macieira wrote:
> >> I'd like to propose a change of policy in the KDE libraries: remove
> >> all virtual_hook functions from QObject-derived classes.
> >>
> >> The reason for that is that we *already* have a virtual_hook function
> >> in those classes and it's called qt_metacall. It's automatically
> >> generated by moc, so we're safe that it'll always exist.
> >
> >Another way to preserve BC is to use the visitor/double dispatch
> > pattern. It can be argued to be a bit heavy code-wise, but achieves the
> > goal and can also be fast, depending on various factors. Major
> > pros/cons:
>
> Would you mind elaborate on what that is?
Ok, attached is a visitor pattern discussion. I'm told it is in GOF's Pattern
Design book, you can read about it in wikipedia, google for it, etc. I might
very well be "wrong" on this, show an incomplete picture, and so forth. I
have never seen anyone use it for the purpose of preserving BC, but by my
common sense(TM) it should be possible to use it that way.
I use the visitor pattern in kdenonbeta/kdom/xpath, but that's mainly for
other reasons(not for preserving BC).
Cheers,
Frans
["visitor_example.cpp" (text/x-c++src)]
class AStayBC;
class BStayBC;
class Visitor
{
public:
virtual char *visit(AStayBC *operand) const = 0;
virtual char *visit(BStayBC *operand) const = 0;
};
/**
* This class and sub-classes must stay binary compatible.
*/
class StayBC
{
public:
virtual char *accept(const Visitor &visitor) = 0;
};
class AStayBC : public StayBC
{
virtual char *accept(const Visitor &visitor)
{
return visitor.visit(this);
}
};
class BStayBC : public StayBC
{
virtual char *accept(const Visitor &visitor)
{
return visitor.visit(this);
}
};
/*
* Now, let's say we want to extend one of the StayBC sub-classes
* in a polymorphic way.
*
* First a Visitor sub-class which provides the "implementation" of the
* extension:
*/
class Extension : public Visitor
{
virtual char *visit(AStayBC *This) const
{
/* @p This is the 'this' pointer of the class we are
* extending, so to speak. */
return "AStayBC";
}
virtual char *visit(BStayBC *This) const
{
return "BStayBC";
}
};
/*
* And now, use Extension:
*/
void doIt()
{
StayBC *sbc = new BStayBC();
Extension ext;
char *result = sbc->accept(ext);
/* We've now managed to perform a polymorphic function call
* without touching the classes which the function call's "this"
* pointer is using. */
}
/*
* There are various modifications one can do here:
*
* - Change the constness of accept() and visit()
* - Make the return value(char *, in this case) a generic class such
* that different return values can be used. Basically: "class VisitorResult{};"(or
* sub-class a Shared class or sth like that), which is sub-classed.
* - One can make the accept() function take additional arguments which it pass on to
* visit(). For example, an int such that one can pass an enum(it looses typing though).
* - Provide default implementations of accept()/visit() which returns default constructed
* values. This avoids that sub-classes have to provide dummy implementations if they
* for some reason are not of interest.
* - One can deploy some of the boiler plate code with templates, especially if one uses
* the visitor pattern for several class hierarchies. (I think boost has somekind of
* visitor support.)
*
* Drawbacks with the visitor pattern:
*
* - It isn't an "uncontrained adding of virtual functions", to be exact. The calling convention
* is different, and what arguments that are allowed to be passed cannot be alterered.
* - It is rather heavy. For adding a virtual function, one needs to create a class.
*
* Advantages:
*
* - It do provide a rather nifty call dispatching mechanism, which, if sufficient, works fine.
* - It allows someone to extend a class hierarchy without sub-classing it.
*
* In some cases a visitor pattern can as a side effect provide a mechanism for preserving
* BC(even though its primary purpose is something else). It's not a perfect, all-in-one
* solution, but if the scenario fits, it fits.
*/
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic