simulating "static pure virtual" methods

C

cppaddict

Hi,

I know that it is illegal in C++ to have a static pure virtual method,
but it seems something like this would be useful when the following 2
conditions hold:

1. You know that every one of your Derived classes will need to
implement some method, but implement it differently, and that the base
class cannot implement it. This is where pure virtual comes in.

2. You know that for every one of your Derived classes, the method
never uses or alters member data. Thus it should be static.

To give a concrete example.

Say you have an abstract Document class, which has a method called
processDocument:

void processDocument() {
if (isApproved(_documentAuthor))
callSomeNonVirtualFunction();
else
callAnotherNonVirtualFunction();
}

Just to take an easy example, let's say that we know isApproved() is
some silly function of the author's name, which is passed in as an
arguement. Maybe for a derived KinkosDocument, isApproved() returns
true if the author's name begins with "A", and is otherwise false.
For some other derived class the rule would be different, but always a
function of the author's name itself.

So we have the following:

1. isApproved() should not be implemented in the base Document class.

2. isApproved() must be implemented in any derived concrete class.

3. isApproved() must be a simple function of a string.

What is the right design for a situation like this?

Thanks,
cpp
 
S

Sharad Kala

cppaddict said:
Hi,

I know that it is illegal in C++ to have a static pure virtual method,
but it seems something like this would be useful when the following 2
conditions hold:
Perhaps you need something like this -

struct A{
virtual void foo() =0;
};

struct B : A{
void foo(){
staticB();
}
static void staticB(){}
};

struct C : A{
void foo(){
staticC();
}

static void staticC(){}
};

int main()
{
}

-Sharad
 
K

Karl Heinz Buchegger

cppaddict said:
Hi,

I know that it is illegal in C++ to have a static pure virtual method,
but it seems something like this would be useful when the following 2
conditions hold:

1. You know that every one of your Derived classes will need to
implement some method, but implement it differently, and that the base
class cannot implement it. This is where pure virtual comes in.

2. You know that for every one of your Derived classes, the method
never uses or alters member data. Thus it should be static.

To give a concrete example.

Say you have an abstract Document class, which has a method called
processDocument:

void processDocument() {
if (isApproved(_documentAuthor))
callSomeNonVirtualFunction();
else
callAnotherNonVirtualFunction();
}

Just to take an easy example, let's say that we know isApproved() is
some silly function of the author's name, which is passed in as an
arguement. Maybe for a derived KinkosDocument, isApproved() returns
true if the author's name begins with "A", and is otherwise false.
For some other derived class the rule would be different, but always a
function of the author's name itself.

plus - and this is important - the type of Document which should
check the name. So in the above you simply cannot have a call
to isApproved only. It needs to be some class member. But then
you need an object of that class to determine the dynamic
type of the Derived class and hence isApproved can be
a normal virtual member function of that class.
There is nothing a static method can do better or worse
in this case. You still need an object to call the method
to identify the context in which the call should be made.

Static functions are usefull if you don't want to specify
any context but use the class as a sort of 'namespace', to avoid
a free standing function. In your example the function cannot
be freestanding, thus static isn't of any use to this problem.
 
J

Jeff Schwab

cppaddict said:
Hi,

I know that it is illegal in C++ to have a static pure virtual method,
but it seems something like this would be useful when the following 2
conditions hold:

1. You know that every one of your Derived classes will need to
implement some method, but implement it differently, and that the base
class cannot implement it. This is where pure virtual comes in.

2. You know that for every one of your Derived classes, the method
never uses or alters member data. Thus it should be static.

To give a concrete example.

Say you have an abstract Document class, which has a method called
processDocument:

void processDocument() {
if (isApproved(_documentAuthor))
callSomeNonVirtualFunction();
else
callAnotherNonVirtualFunction();
}

Just to take an easy example, let's say that we know isApproved() is
some silly function of the author's name, which is passed in as an
arguement. Maybe for a derived KinkosDocument, isApproved() returns
true if the author's name begins with "A", and is otherwise false.
For some other derived class the rule would be different, but always a
function of the author's name itself.

So we have the following:

1. isApproved() should not be implemented in the base Document class.

2. isApproved() must be implemented in any derived concrete class.

3. isApproved() must be a simple function of a string.

What is the right design for a situation like this?

There's no need for the base class to declare the method. The point of
virtual methods is to allow subclass-specific behavior through pointers
(or references) to objects of a base type. You can't have a pointer to
an entire class, so there's no point in having a static virtual method.

If client code expects some feature of a class, and that feature (e.g. a
static method with a particular name) is missing, you will get a
compile-time error.

If you want to ensure a priori that each of a group of types can be used
in particular ways, you can write a "constraints" class to express the
requirements. You do have to instantiate the class for each type you
want to check explicitly. If you find this approach useful, check out
the Boost Concept Checking library.

struct A
{
// Each subclass should have a default constructor, and a static
// method called "foo" that can be called with no arg's.
//
// Instantiate A::Check_constraints for each type derived from A
// to check these requirements.

template< typename T >
struct Check_constraints
{
static void check_for_default_constructor ( )
{
T t = T( );
}

static void check_for_static_method_foo( )
{
T::foo( );
}
};
};

struct B: A
{
static void foo( ) { }
B ( ) { }
};

struct C: A
{
C ( ) { }
};

/* Explicit instantiations verify that B and C meet A's requirements.
*/
template class A::Check_constraints< B >;
template class A::Check_constraints< C >;
 
J

jeffc

cppaddict said:
Hi,

I know that it is illegal in C++ to have a static pure virtual method,
but it seems something like this would be useful when the following 2
conditions hold:

1. You know that every one of your Derived classes will need to
implement some method, but implement it differently, and that the base
class cannot implement it. This is where pure virtual comes in.

2. You know that for every one of your Derived classes, the method
never uses or alters member data. Thus it should be static.

Why should it be static just because of that? If it's static, it can't be
virtual. Virtual is what allows overriding.
 
A

Andy Venikov

cppaddict said:
Hi,

I know that it is illegal in C++ to have a static pure virtual method,
but it seems something like this would be useful when the following 2
conditions hold:

1. You know that every one of your Derived classes will need to
implement some method, but implement it differently, and that the base
class cannot implement it. This is where pure virtual comes in.

2. You know that for every one of your Derived classes, the method
never uses or alters member data. Thus it should be static.

To give a concrete example.

Say you have an abstract Document class, which has a method called
processDocument:

void processDocument() {
if (isApproved(_documentAuthor))
callSomeNonVirtualFunction();
else
callAnotherNonVirtualFunction();
}

Just to take an easy example, let's say that we know isApproved() is
some silly function of the author's name, which is passed in as an
arguement. Maybe for a derived KinkosDocument, isApproved() returns
true if the author's name begins with "A", and is otherwise false.
For some other derived class the rule would be different, but always a
function of the author's name itself.

So we have the following:

1. isApproved() should not be implemented in the base Document class.

2. isApproved() must be implemented in any derived concrete class.

3. isApproved() must be a simple function of a string.

What is the right design for a situation like this?

Thanks,
cpp

Static functions can't be virtual for a reason. You use them
when you want to execute something class-specific without any
context, meaning without an object of that class. Virtual functions
make no sense without objects. In other words, to call a virtual
function, you need an object. But if you have an object, you don't
need the function to be static.

If what you want is for for each class to have it's own
implementation of isApproved, but be called not through the object
invocation, but through a class invocation, then you can achieve that by
just overloading the isApproved. The derived class's isApproved will
hide the base class's isApproved when you do this: Derived::isApproved.
The problem here is now you'll have to duplicate processDocument() in
each derived class, because parent's processDocument will only call
parent's isApproved().

If you make isApproved a public function, then you can use
a template function like this:

template <class T> void processDocument(documnetAuthor)
{
if (T::isApproved(documentAuthor))
T::SomeNonVirtualF;
else
T::SomeOtherNonVirtualF;
}

and call it like this

processDocument<DerivedDoc>(documentAuthor);

Andy.
 
V

Victor Bazarov

Andy said:
cppaddict said:

Static functions can't be virtual for a reason. You use them
when you want to execute something class-specific without any
context, meaning without an object of that class. Virtual functions
make no sense without objects. In other words, to call a virtual
function, you need an object. But if you have an object, you don't
need the function to be static.
[...]

Andy, take a look at the recent thread in comp.std.c++ about static
virtual functions (titled "static member functions and 'virtual'",
started by David Whipp) and the explanation why they can be of use,
perhaps you will not be as rigid after that.

Victor
 
C

cppaddict

Karl,

Thanks for your reply. I've got a couple more questions though...
Static functions are usefull if you don't want to specify
any context but use the class as a sort of 'namespace', to avoid
a free standing function. In your example the function cannot
be freestanding, thus static isn't of any use to this problem.

I think my point is that my the function isApproved() could just as
well be freestanding. It just processes a string passed to it and
returns true/false. The only reason that I don't want it to be
freestanding is that the only place I'm using it is in this class, and
I want to make that connection clear by having it be a member
function. Thus your description of static functions only being useful
as a sort of 'namespace' applies perfectly here. It's just that I
also want to say syntactically: "This function will be implemented by
all derived classes."

To give you an idea of my priorities, right now my solution is simply
to have isApproved be a virtual function, and ignore the fact that it
doesn't really require any context. Indeed, to give it context, I
could have it operate on _documentAuthor directly instead of passing
that in as an argument. Then I would no longer feel that it "should"
be static. Perhaps that is the real issue here....

Thanks for any further thoughts,
cpp
 
D

Dave Townsend

I think in this example you'd be better off using a "strategy" design
pattern
or something else like policy classes.

In the strategy pattern approach, you will have a data member which
provides the IsApproved() method. You can construct the class by
passing such an approval object as a parameter to the constructor.
In this way, the workings of the class can be left alone, the approval
object provides the variations in the approval. This is good if all that
is varying is the approval behavior, not the document behavior.


for example:

class Document
{
public:
Document( Approver* approver );

};

class Approver
{
public:
virtual bool isApproved()=0;
};

class KinkoApprover
{
public:
virtual bool isApproved () { ....do approval ...}
};
class OfficeDepotApprover
{
public:
virtual bool isApproved () { ....do approval ...}
};

Document* kinkoDoc = new Document( new KinkoApprover() );
Document* officeDepotDoc = new Document( new OfficeDepotApprover() );


dave
 
C

cppaddict

In the strategy pattern approach, you will have a data member which
provides the IsApproved() method. You can construct the class by
passing such an approval object as a parameter to the constructor.
In this way, the workings of the class can be left alone, the approval
object provides the variations in the approval. This is good if all that
is varying is the approval behavior, not the document behavior.

Dave,

Thanks for that. That would work here and seems appropriate. But
how, in general, does one decide when a Strategy Pattern is
appropriate and when a virtual function is appropriate?

Both methods seem to allow you to separate out implementation from
context.

Thanks again,
cpp
 
D

Dave Townsend

CPP,

You might want to read the chapter in Gof Design Patterns to
review the pros and cons of a strategy, they probably explain
things much better than I can here. Also Martin Fowler's book
on Refactoring I believe illustrates this idea quite well.

One point, the introduction of the strategy pattern doesn't necessarily
mean the elimination of the virtual function in the document class :

virtual bool isApproved( ){ return _approver->isApproved( authorName) ;};

Here the approval call is just forwarded to the strategy object, so the
public interface to the class would be the same as in your original idea.


I think in your situation where you potentially could have a lot of
different "approval" strategies but only one real document class,
the strategy is the way to go. In addition, new approver objects can
be introduced without changing the document class. Also, the document
base class can be further derived and used with these or other strategies.

Another consideration would if other strategies could be factored out
of your document class, so you are left with a skeletal class with
a bunch of different strategies which do the real work. For instance,
document
persistence could be handled through another strategy object, so you could
"persist" to a memory
stream or file medium. The strategy approach makes this more flexible,
so you could have a memory-stream-kinko document as well as a file-persist
office-depot document etc. This would be too awkward if you have to
declare/define classes for every variation. Now introduce another variation
- UpperCase document/LowerCase - ( I know its a bit contrived but I'm trying
to illustrate a point.)

I tend to use strategy patterns a lot, its my favourite! Sometimes my
strategy object itself is
extrodinarily very simple and designed for only one particular purpose, I
can write
a simple object correctly, but I might goof on a more complex one!

Hope that helps!

dave
 
A

Andy Venikov

Andy, take a look at the recent thread in comp.std.c++ about static
virtual functions (titled "static member functions and 'virtual'",
started by David Whipp) and the explanation why they can be of use,
perhaps you will not be as rigid after that.

Victor

Victor,
I'm aware of the issue. In fact, I was trying to explain it and a
possible solution in my reply to the OP.

The problem here is now you'll have to duplicate processDocument() in
each derived class, because parent's processDocument will only call
parent's isApproved().
If you make isApproved a public function, then you can use
a template function like this:
template <class T> void processDocument(documnetAuthor)
{
if (T::isApproved(documentAuthor))
T::SomeNonVirtualF;
else
T::SomeOtherNonVirtualF;
}
and call it like this
processDocument<DerivedDoc>(documentAuthor);
</End snippet>

As you can see, the solution I came up with is exactly the same
Alberto Barbatti used in his post. It won't work if we need to
call non-public functions though. I'm still thinking about a
way to fix that.
What we need is sort-of "base template function". Template
function defined in the base that is instanciated in each
derived class with that class's type.

Thanks though,
Andy.
 
A

Andy Venikov

I'm still thinking about a
way to fix that.
What we need is sort-of "base template function". Template
function defined in the base that is instanciated in each
derived class with that class's type.

Here's a possible solution. It looks ugly though.
The idea is to have in each class a static pointer
to function initialized with an instatiation of a base
class's template function parameterized with class's type.

Here goes:

struct Base
{
template <class T>
static void Func1()
{
cout << "template<> Func1 called." << endl;
T::Func2();
}

static void (*func1)();

static void Func2()
{
cout << "Base::Func2()" << endl;
}
};

void (*Base::func1)() = &Base::Func1<Base>;


struct Derived : Base
{
static void Func2()
{
cout << "Derived::Func2()" << endl;
}

static void (*func1)();
};
void (*Derived::func1)() = &Base::Func1<Derived>;

int main(int argc, char ** argv)
{
Base::func1();
Derived::func1();

return 0;
}


Cheers,
Andy.
 

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
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top