Something like a final method

M

Marcel Müller

Hi,

I am seeking for a solution for the following performance issue:

class Interface
{public:
virtual int GetStatus() = 0;
};

class AbstractBase : public Interface
{private:
int Status;
public:
virtual int GetStatus() { return Status; } // Never overridden
};


If I call GetStatus() through a pointer to AbstractBase (or any derived
class) the call cannot be inlined because it is a virtual function. Of
course, there is no other way when using a pointer to Interface. But
there are many calls via pointers to AbstractBase or some of the derived
classes. I would like to avoid these function calls since almost any
method of derived classes do it and the implementation of GetStatus is
really trivial.

Is there any better solution than renaming the method of Interface to
GetStatusByInterface() or something like that?


Marcel
 
L

litb

I would like to avoid these function calls since almost any
method of derived classes do it and the implementation of GetStatus is
really trivial.

Is there any better solution than renaming the method of Interface to
GetStatusByInterface() or something like that?

Looks like the first practical use of [[final]] i noticed. Anyway, why
not do it like this:

// --snip--
class Interface
{public:
Interface(int Status):Status(Status) { }
virtual ~Interface() { }
int GetStatus() { return Status; }

protected:
int Status;
};

class AbstractBase : public Interface
{
AbstractBase():Interface(10){}
};
// --snap--

Another idea could be to abuse overload resolution. But that looks
like an evil way. Though it seems to work

// --snip--
struct not_preferred_t { } not_preferred;
struct preferred_t : not_preferred_t { } preferred;

struct A {
virtual int f(not_preferred_t = not_preferred) = 0;
};

struct B : A {
// don't prefer this one. explicitly give argument not_preferred
// to call it
virtual int f(not_preferred_t) {
return 42;
}

// prefer this one
int f(preferred_t = preferred) {
return 42;
}

};

int main() {
A *a = new B;
cout << a->f(); // slow :(
cout << a->f(preferred); // slow :(

B *b = static_cast<B*>(a);
cout << b->f(not_preferred); // slow :(
cout << b->f(preferred); // fast :)
cout << b->f(); // fast :)

delete b;
}
// --snap--
 
A

Alf P. Steinbach

* Marcel Müller:
I am seeking for a solution for the following performance issue:

class Interface
{public:
virtual int GetStatus() = 0;
};

class AbstractBase : public Interface
{private:
int Status;
public:
virtual int GetStatus() { return Status; } // Never overridden
};


If I call GetStatus() through a pointer to AbstractBase (or any derived
class) the call cannot be inlined because it is a virtual function. Of
course, there is no other way when using a pointer to Interface. But
there are many calls via pointers to AbstractBase or some of the derived
classes. I would like to avoid these function calls since almost any
method of derived classes do it and the implementation of GetStatus is
really trivial.

Is there any better solution than renaming the method of Interface to
GetStatusByInterface() or something like that?

Redesign.

Which you probably need to do anyway, because "status", "get" and lack of
"const" are all design smells.

If you decide to keep the status (it would probably be better to get rid of it
because status checking implies that it's needed implies that valid operations
depend on it implies that you have states that are so distinct they're more like
distinct types, hence e.g. Envelope/Letter pattern would help), then, keeping
it, it might go like this:

class Interface
{
public:
virtual ~Interface() {}
virtual int status() const = 0;
};

class SimpleStatusImpl: public virtual Interface
{
protected:
int myStatus;
public:
SimpleStatusImpl(): myStatus(0) {}
virtual int status() const { return nonVirtualStatus(); }
int nonVirtualStatus() const { return myStatus; }
};

class AbstractBase: public virtual Interface
{
// Nothing about status here.
};

class SimpleConcrete
: public AbstractBase
, public SimpleStatusImpl
{
};

The client code that wants fast non-virtual status checking can just call
nonVirtualStatus. Which can be redefined in derived classes. It's up to the
client code to decide whether it knows enough to be able to use it.

I think that if I'd been forced to do this status thing, I'd keep the name
"nonVirtualStatus", because it communicates the purpose of that accessor.


Cheers & hth.,

- Alf


PS: Don't forget the first law of optimization: *measure*. ;-)
 
A

Alf P. Steinbach

* blargg:
Use a forwarding function:

class Base {
public:
void f() { vf(); } // forward to virtual version
protected:
virtual void vf() = 0;
};

class Derived : public Base {
protected:
virtual void vf();
};

class Final : public Derived {
public:
void f() { Final::vf(); } // bypass virtual call
protected:
virtual void vf();
};

void user( Base& b, Derived& d, Final& f )
{
b.f(); // dynamic call to vf
d.f(); // dynamic call to vf
f.f(); // static call to Final::vf
}

Note how it's fine if you pass a Final via a Base&; you'll get a virtual
call. This is one instance where hiding a (non-virtual) base class
function isn't problematic.

In my earlier response I did it the other way, letting the virtual routine
forward to the non-virtual one; in terms of above code, vf() calling f().

I'm not sure if I thought it through at that time or simply grabbed back in my
hind-brain for a relevant pattern, but anyway there's a reason for that.

Namely, as indicated in your code, that any class that customizes the f()
calling vf() scheme must be (documented as or restricted to be) final, lest
someone derives a class DerivedFromFinal where f is again redefined. In that
case treating a DerivedFromFinal as a Final can invoke the wrong implementation
of f(). That's also /technically/ possible with calls going the other way, but
with f() calling vf() it's not apparent from the calling code whether o.f() is a
virtual call (safe) or non-virtual (unsafe) call, whereas with vf() calling f()
this is very clear: f() is always non-virtual, and vf() is always virtual.


Cheers, & hth.,

- Alf


PS: What complicates the whole thing is that no matter what, a derived class
that customizes things must define both f() and vf(). I see no way of ensuring
that. But then I'm a bit tired and perhaps there is a Way, who knows... :)
 
J

James Kanze

Use a forwarding function:
class Base {
public:
void f() { vf(); } // forward to virtual version
protected:
virtual void vf() = 0;
};
class Derived : public Base {
protected:
virtual void vf();
};
class Final : public Derived {
public:
void f() { Final::vf(); } // bypass virtual call
protected:
virtual void vf();
};
void user( Base& b, Derived& d, Final& f )
{
b.f(); // dynamic call to vf
d.f(); // dynamic call to vf
f.f(); // static call to Final::vf
}
Note how it's fine if you pass a Final via a Base&; you'll
get a virtual call. This is one instance where hiding a
(non-virtual) base class function isn't problematic.

Right pattern, but you've inverted the actions:

class Interface
{
public:
int getStatus() const
{
return doGetStatus() ;
}
private:
virtual int doGetStatus() const = 0 ;
} ;

class AbstractBase : public Interface
{
public:
int getStatus() const
{
return currentStatus ;
}
private:
virtual int doGetStatus() const
{
return getStatus() ;
}
private:
int myStatus ;
} ;

It's a fairly standard pattern, I think. (But judging from
other things I've considered "standard patterns", this may
just be wishful thinking. Hasn't anyone read Barton and
Nackman?)
 
M

Marcel Müller

James said:
Right pattern, but you've inverted the actions:

class Interface
{
public:
int getStatus() const
{
return doGetStatus() ;
}
private:
virtual int doGetStatus() const = 0 ;
} ;

class AbstractBase : public Interface
{
public:
int getStatus() const
{
return currentStatus ;
}
private:
virtual int doGetStatus() const
{
return getStatus() ;
}
private:
int myStatus ;
} ;

Thanks! This is the best suggestion so far. The syntax for the caller is
symmetric without a performance impact. I don't know why something like
that did not come into my mind.
It's a fairly standard pattern, I think.

At least I did not use it so far.


Marcel
 
A

Alf P. Steinbach

* Marcel Müller:
Thanks! This is the best suggestion so far. The syntax for the caller is
symmetric without a performance impact. I don't know why something like
that did not come into my mind.

Note that James' code is essentially the same as blaarg's.

And what it means that

o.getStatus()

may perform a virtual or a non-virtual call depending on the type of 'o'.

The code I presented does not suffer from that problem.


At least I did not use it so far.

The pattern used in the Interface is standard, in the sense of being quite
common and established as "good" (it's a shame it can't be used with Java).

The inversion of that pattern in AbstractBase, in order to avoid virtual calls,
is not standard.

It means that (as with the code I presented, and any solution, but it's in your
requirements so can't be avoided)

1. the wrong implementation of getStatus can easily be called.

And as noted above (not the case with the code I presented) it means that

2a. one can not see by local inspection of call whether a call is non-virtual
or not, and worse,

2b. if you have the wrong static type for an object, e.g.
AbstractBase& where the dynamic type is DerivedWithCustomStatus, then a
cast is needed to get the correct virtual call.

Finally, (not the case with the code I presented)

3. by adding the status implementation directly in AbstractBase that
implementation is forced as baggage on derived classes using another
implementation,

which presumably there will be, otherwise the status implementation can and
should be hoisted up in Interface (which should then perhaps be called something
else).


Cheers & hth.,

- Alf
 
M

Marcel Müller

Alf said:
Note that James' code is essentially the same as blaarg's.

And what it means that

o.getStatus()

may perform a virtual or a non-virtual call depending on the type of 'o'.

The code I presented does not suffer from that problem.

I dont't see any problem here.

And as noted above (not the case with the code I presented) it means that

2a. one can not see by local inspection of call whether a call is
non-virtual
or not, and worse,

Well, using an interface all calls are virtual, of course.
2b. if you have the wrong static type for an object, e.g.
AbstractBase& where the dynamic type is DerivedWithCustomStatus,
then a
cast is needed to get the correct virtual call.

No. The method is never overridden except for the interface
implementation. Otherwise I would not have asked for 'final'.

Finally, (not the case with the code I presented)

3. by adding the status implementation directly in AbstractBase that
implementation is forced as baggage on derived classes using another
implementation,

This is intended. Status is part of the services of AbstractBase.

In fact the two interface implementations (and their derived classes)
are something like the envelopes and letters as you mentioned. Any
envelope has a immutable strong reference to a letter and adds some
features around an abstract letter. But the envelope is also allowed to
override a few properties of the letter, including the status for
visualization (now this is a proxy pattern). Previously these classes
were used in distinct code locations and did not have any common
interface (except for the one used for intrusive reference counting).
Now I have code locations that do not need to know whether they
currently use the proxy (and envelope) or the object itself. This is
another kind of usage that only addresses the proxy pattern and needs a
common interface. But exactly the same functions are used inside the
letter's class tree widely, and now they became non-inline.


Marcel
 
L

litb

Right pattern, but you've inverted the actions:

    class Interface
    {
    public:
        int             getStatus() const
        {
            return doGetStatus() ;
        }
    private:
        virtual int     doGetStatus() const = 0 ;
    } ;

    class AbstractBase : public Interface
    {
    public:
        int             getStatus() const
        {
            return currentStatus ;
        }
    private:
        virtual int     doGetStatus() const
        {
            return getStatus() ;
        }
    private:
        int             myStatus ;
    } ;

Oh noes! That's way cleaner than my scary hax :) Yeah it's also very
Standard, very much used in C++ standard classes. However i don't
think that the inversion found in the derived class is all that
standard? Seen it for the first time now, though i guess that should
be the way to go for the questioner anyway. May i recommend to him
"NonVirtualInterface" found here: http://www.gotw.ca/publications/mill18.htm
, which is the basic gist of that. Have fun!
 
J

James Kanze

* Marcel Müller:
Note that James' code is essentially the same as blaarg's.

Sort of. Blargg uses an explicit scope qualifier to short
circuit the virtual-ness; I just put the implementation in the
non-virtual function.
And what it means that

may perform a virtual or a non-virtual call depending on the
type of 'o'.

Which is what is wanted, I think. If the caller knows the type,
it gets the non-virtual; if it doesn't, it gets the virtual.
The code I presented does not suffer from that problem.

Yours may perform a virtual or a non-virtual call depending on
the name of the function being called.

I prefer my solution, but admittedly, that may be only because
I'm more used to it. In the original example in Barton and
Nackman, the function was operator[], however, and you can't
give that one a different name, and still have it work as an
operator.
The pattern used in the Interface is standard, in the sense of
being quite common and established as "good" (it's a shame it
can't be used with Java).
The inversion of that pattern in AbstractBase, in order to
avoid virtual calls, is not standard.

It's standard in the sense that it's a documented and
established pattern. I'd argue that any competent C++
practitioner should be familiar with it, but judging from
discussions in other threads, that's likely just wishful
thinking on my part.
It means that (as with the code I presented, and any solution,
but it's in your requirements so can't be avoided)
1. the wrong implementation of getStatus can easily be called.

Possibly. Arguably, there should never be more than one
implementation in any given class.
And as noted above (not the case with the code I presented) it
means that
2a. one can not see by local inspection of call whether a call is non-virtual
or not, and worse,
2b. if you have the wrong static type for an object, e.g.
AbstractBase& where the dynamic type is DerivedWithCustomStatus, then a
cast is needed to get the correct virtual call.
Finally, (not the case with the code I presented)
3. by adding the status implementation directly in AbstractBase that
implementation is forced as baggage on derived classes using another
implementation,

My understanding was that that was the purpose of AbstractBase;
to provide a "partial" implementation common to a large number
of derived classes. A derived class that doesn't need or want
this implementation derives directly from Interface, not from
AbstractBase. (At least, that's the way the AbstractXxx are
used in the Java library.) On the other hand, I do like your
idea of separating the particular aspect of the implementation
out into a separate, mixin class, rather than taking an all or
nothing approach to the partial implementation.
which presumably there will be, otherwise the status
implementation can and should be hoisted up in Interface
(which should then perhaps be called something else).

I suspect that the model being used is the same as that in e.g.
javax.swing.Action/javax.swing.AbstractAction. But you're
right: in C++, there's no reason to force everything possibly
shared between the concrete classes into a single class---mixins
are a much better solution.
 
J

James Kanze

However i don't think that the inversion found in the derived
class is all that standard?

It's documented in Barton and Nackman. IMHO, the Barton and
Nackman is one book that everyone should read; although dated
(no namespaces, <iostream.h>, etc.), it covers a number of
points that I've not seen discussed elsewhere. But everytime I
mention a pattern from Barton and Nackman, everyone seems
surprised by it.
 
J

James Kanze

James said:
blargg wrote:
[...]
How does your version perform any differently?

It corresponds to a documented pattern (from Barton and
Nackman). That's all, really. (I don't particularly care for
the scope resolution operator, but that's more a question of
personal taste---I can't think of any good reason behind my
prejudice.)
 

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

No members online now.

Forum statistics

Threads
474,161
Messages
2,570,892
Members
47,428
Latest member
RosalieQui

Latest Threads

Top