switch statement to detect handling of ALL derived classes

H

Hicham Mouline

Imagine we have an abstract base class ABC and derived classes D1, D2, ...
Dn

I am being told a code pattern to "enforce" all cases are handled is such:


enum ABCTypes { D1Tag, D2Tag, .... DnTag };

const ABC& base

ABCTypes t = base.getTag();
swich(t)
{
case D1Tag:
...
case DnTag:
}

without the default branch.


If you add a Dnplus1 derived class and its tag Dnplus1Tag in the enum
ABCTypes ,
all code patterns with the switch-case will generate an error if you forget
to handle the Dnplus1 case.

1) Does the standard "require" handling all cases of the enum? Or does it
only say a conforming implementation should print a warning?
2) Are there opinions on this style? I don't like the use of the getTag()
method in the ABC class to facilitate this style.

3) Is there a way to use boost::mpl and/or boost::preprocessor to generate
the switch-case statement?

rds,
 
I

Ian Collins

Hicham said:
Imagine we have an abstract base class ABC and derived classes D1, D2, ...
Dn

I am being told a code pattern to "enforce" all cases are handled is such:


enum ABCTypes { D1Tag, D2Tag, .... DnTag };

const ABC& base

ABCTypes t = base.getTag();
swich(t)
{
case D1Tag:
...
case DnTag:
}

without the default branch.


If you add a Dnplus1 derived class and its tag Dnplus1Tag in the enum
ABCTypes ,
all code patterns with the switch-case will generate an error if you forget
to handle the Dnplus1 case.
Eh?

1) Does the standard "require" handling all cases of the enum? Or does it
only say a conforming implementation should print a warning?
Neither.

2) Are there opinions on this style? I don't like the use of the getTag()
method in the ABC class to facilitate this style.

It's horrible, why not just use virtual functions?
 
H

Hicham Mouline

Ian Collins said:
g++ prints a warning when not all enum values are handled in the switch
case.
That is a choice made but that implementation then.

It's horrible, why not just use virtual functions?
I also don't like it.... But I need to show an alternative.The processing done in the switch case is not inherently related to the ABC.
I'd rather not put that processing in a member virtual function of ABC, but
rather some external function that takes ABC
In that function, I could use

if (dynamic_cast<D1*>( base ))
///
if (dynamic_cast<D2*>( base ))
///
....
if (dynamic_cast<Dn*>( base ))
///
but with this, I can't even get a warning if I am missing Dnplus.

Is there a different way of using the virtuality without writing member
virtual functions?

rds,
 
A

Alf P. Steinbach

* Hicham Mouline:
I could use

if (dynamic_cast<D1*>( base ))
///
if (dynamic_cast<D2*>( base ))
///
...
if (dynamic_cast<Dn*>( base ))
///
but with this, I can't even get a warning if I am missing Dnplus.

Is there a different way of using the virtuality without writing member
virtual functions?

Instead of dynamic cast just use a virtual member routine, and call that.


Cheers & hth.,

- Alf
 
I

Ian Collins

Hicham said:
g++ prints a warning when not all enum values are handled in the switch
case.
That is a choice made but that implementation then.
I also don't like it.... But I need to show an alternative.
Why?

The processing done in the switch case is not inherently related to the ABC.
I'd rather not put that processing in a member virtual function of ABC, but
rather some external function that takes ABC
In that function, I could use

if (dynamic_cast<D1*>( base ))
///
if (dynamic_cast<D2*>( base ))
///
....
if (dynamic_cast<Dn*>( base ))
///
but with this, I can't even get a warning if I am missing Dnplus.

That's even worse.
Is there a different way of using the virtuality without writing member
virtual functions?

What's wrong with

struct ABC {
virtual void doSomething() = 0;
};

struct D1 : ABC {
void doSomething() { // does something }
};

....

base.doSomething();

All derived classes must provide doSomething(), so no case can be left
out by mistake.
 
H

Hicham Mouline

Alf P. Steinbach said:
* Hicham Mouline:

Instead of dynamic cast just use a virtual member routine, and call that.


Cheers & hth.,

- Alf
that's what I don't want to use. a "member" virtual function.
 
H

Hicham Mouline

Ian Collins said:
That's even worse.


What's wrong with

struct ABC {
virtual void doSomething() = 0;
};

struct D1 : ABC {
void doSomething() { // does something }
};

...

base.doSomething();

All derived classes must provide doSomething(), so no case can be left out
by mistake.

Because doSomething is not immediately relevant to ABC.
It's 3rd party code using my hierarchy that I provide for them.
 
J

James Kanze

g++ prints a warning when not all enum values are handled in
the switch case.

It doesn't when I use it. You can (and should) turn such stupid
warnings off; it's quite frequent to use a switch to catch just
a couple of the cases (which have special treatment).
That is a choice made but that implementation then.

Yep. Most implementations have one or two really stupid
warnings.
I also don't like it.... But I need to show an alternative.

Virtual functions, like Ian said.
The processing done in the switch case is not inherently
related to the ABC. I'd rather not put that processing in a
member virtual function of ABC, but rather some external
function that takes ABC In that function, I could use

Check out the visitor pattern. Or if worse comes to worse, a
map of type_info to functional objects. (The visitor pattern
does require some support in the hierarchy, but it is a very
generic support, with no real processing.)
if (dynamic_cast<D1*>( base ))
///
if (dynamic_cast<D2*>( base ))
///
...
if (dynamic_cast<Dn*>( base ))
///
but with this, I can't even get a warning if I am missing
Dnplus.
Is there a different way of using the virtuality without
writing member virtual functions?

Without any member virtual functions, you'll have to implement
the virtuality yourself, using std::map. But the virtual
functions necessary for the visitor pattern are quite trivial.
And you'll get a compile time error if you fail to handle one of
the derived classes. (Using std::map, you won't get an error
until runtime.)
 
H

Hicham Mouline

Stephen Howe said:
A feature is designed for the language and later we have someone say,
"I dont want to use this feature, how do I emulate it? "

They then discover that the emulation has drawbacks (switch statement
missing a case label). That drawback was the raison d'etre for virtual
functions.

Stephen Howe
I don't have a choice. The classes cannot be changed. 3rd party.
 
T

Tim Hockin

"Stephen Howe" <sjhoweATdialDOTpipexDOTcom> wrote in message

>that's what I don't want to use.   a "member" virtual function.




I don't have a choice. The classes cannot be changed. 3rd party.

You only have a base-class pointer, and you want to operate on the
derived class. Yep. dynamic_cast or enum. You've got to manage it
manually. Keep a table of function pointers and jump into it based on
the enum?
 

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,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top