C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

typedef vs. class

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
mzdude
Guest





PostPosted: Wed Jul 27, 2005 5:35 pm    Post subject: typedef vs. class Reply with quote



I'm in the process of cleaning up code that has evolved over the last
6-7 years. In many cases a header file will contain the following:

hdr1.h

struct MyStuff {
// stuff
};
typedef std::vector< MyStuff > StuffArray;

which is O.K. Then another header will have

hdr2.h
#include "hdr1.h" // required for StuffArray definition
void MyFunct( const StuffArray &sa );


which requires the inclusion of hdr1.h for the typedef. I have found
that redefining the original typedef as a class:

hdr1.h
struct MyStuff {
// stuff
};
class StuffArray : public std::vector< MyStuff > {};

I can now do the following in hdr2.h

class StuffArray; // just a forward reference
void MyFunct( const StuffArray &sa );

I know that stl containers aren't designed to be base classes, since
they don't have virtual destructors, but in this case I think it's OK.
Are there any significant drawbacks to the class declaration vs the
typedef? In many cases, by using the forward declaration, significant
compile time dependacies get reduced. I have checked this out with
several different versions of a compiler (not noted for it's adherance
to the standard) and it seems to function correctly.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Paul Rosen
Guest





PostPosted: Wed Jul 27, 2005 11:08 pm    Post subject: Re: typedef vs. class Reply with quote



mzdude wrote:

[...]
Quote:
hdr1.h
struct MyStuff {
// stuff
};
class StuffArray : public std::vector< MyStuff > {};

I can now do the following in hdr2.h

class StuffArray; // just a forward reference
void MyFunct( const StuffArray &sa );

I know that stl containers aren't designed to be base classes, since
they don't have virtual destructors, but in this case I think it's OK.
Are there any significant drawbacks to the class declaration vs the
typedef? In many cases, by using the forward declaration, significant
compile time dependacies get reduced. I have checked this out with
several different versions of a compiler (not noted for it's adherance
to the standard) and it seems to function correctly.

I did that a while back and it seems to work and it greatly increases
modularity. I asked a similar question to this list and didn't get any
concrete objections other than "The standard says it's undefined, so you
can't do it."

I personally can't think of a way for it to fail if you don't define any
data in StuffArray. The problem is to make sure that code maintainers
understand that, too. Adding a comment might help that.

I have also yielded to temptation and done the following:

class StuffArray : public std::vector< MyStuff >
{
public:
std::vector< MyStuff >::iterator CoolAlgorithm() const { ... };
};

Again, being careful not to define data. In this case, it is more likely
that the next guy is going to not realize that.

The only coding difference I've seen has something to do with implicit
conversions. I forget the example, but one place in my code didn't
compile because there would have been two implicit conversions.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Éric Malenfant
Guest





PostPosted: Wed Jul 27, 2005 11:09 pm    Post subject: Re: typedef vs. class Reply with quote



A drawback of the inheritance approach is that you loose std::vector's
constructors. For example, with the typedef you could write:
StuffArray some_array(10);
but can't with the version using inheritance.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Francis Glassborow
Guest





PostPosted: Thu Jul 28, 2005 11:18 am    Post subject: Re: typedef vs. class Reply with quote

In article <6gRFe.10038$oZ.5296 (AT) newsread2 (DOT) news.atl.earthlink.net>, Paul
Rosen <prosen (AT) fte (DOT) com> writes
Quote:
class StuffArray : public std::vector< MyStuff
{
public:
std::vector< MyStuff >::iterator CoolAlgorithm() const { ... };
};

Again, being careful not to define data. In this case, it is more likely
that the next guy is going to not realize that.


So the implicit conversion from StuffArray to std::vector<MyStuff> will
never cause problems? You sure?



--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Greg
Guest





PostPosted: Thu Jul 28, 2005 11:53 am    Post subject: Re: typedef vs. class Reply with quote



mzdude wrote:
Quote:
I'm in the process of cleaning up code that has evolved over the last
6-7 years. In many cases a header file will contain the following:

hdr1.h

struct MyStuff {
// stuff
};
typedef std::vector< MyStuff > StuffArray;

which is O.K. Then another header will have

hdr2.h
#include "hdr1.h" // required for StuffArray definition
void MyFunct( const StuffArray &sa );


which requires the inclusion of hdr1.h for the typedef. I have found
that redefining the original typedef as a class:

No, hdr2.h does need to include hdr1.h for the StuffArray typedef. It
just needs the typedef declaration itself. In this situation I would
just copy StuffArray's typedef into hdr2.h or copy it into some other
header file that they both include in common. Note that the original
typedef in hdr1.h has not been deleted, it has only been copied to
another header file. Now the StuffArray typedef is declared for clients
of hdr1.h and also for the clients of hdr2.h and done so without making
the clients of one header file the reluctant clients of the other.

It is perfectly legal in C++ to have multiple typedefs for the same
name - provided that all are alike. If the typedef for StuffArray ever
changes, the downside is that each typedef would have to change
together. But in practice typedefs rarely change, nor are they
difficult to find. And there is little danger of ending up with
typedefs for the same name disagreeing, since the first file that
includes both versions will catch the error. And in practice I've never
ran into a problem with duplicate typdef declarations. In fact it's for
exactly this purpose - of reducing cross dependencies - that duplicate
typedefs were added to the C++ standard.

Greg


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Thu Jul 28, 2005 12:34 pm    Post subject: Re: typedef vs. class Reply with quote

mzdude wrote:

Quote:
I'm in the process of cleaning up code that has evolved over
the last 6-7 years. In many cases a header file will contain
the following:

hdr1.h

struct MyStuff {
// stuff
};
typedef std::vector< MyStuff > StuffArray;

which is O.K. Then another header will have

hdr2.h
#include "hdr1.h" // required for StuffArray definition
void MyFunct( const StuffArray &sa );

which requires the inclusion of hdr1.h for the typedef. I have
found that redefining the original typedef as a class:

hdr1.h
struct MyStuff {
// stuff
};
class StuffArray : public std::vector< MyStuff > {};

I can now do the following in hdr2.h

class StuffArray; // just a forward reference
void MyFunct( const StuffArray &sa );

I know that stl containers aren't designed to be base classes,
since they don't have virtual destructors, but in this case I
think it's OK. Are there any significant drawbacks to the
class declaration vs the typedef?

The most obvious one is that a user who declares a std::vector<
MyStuff >, rather than a StuffArray, can't call your function on
it. If you can assure that uses never use an std::vector<
MyStuff > other than your StuffArray, it's OK. If you can't, I
suspect that it is still looking for trouble.

Quote:
In many cases, by using the forward declaration, significant
compile time dependacies get reduced.

I have checked this out with several different versions of a
compiler (not noted for it's adherance to the standard) and it
seems to function correctly.

As long as you don't try to delete through a pointer to the base
class, or do pointer arithmetic on a base class pointer when you
actually have StuffArray's, you're OK as far as the standard
goes. Since typically, dynamically allocated vectors aren't
that common, and C style arrays of vectors are even rarer, the
risk is limited. Since you aren't allowing the user to use any
of the functions provided for StuffArray if they actually only
have an std::vector, the risk is even more limited.

I'd document the restrictions, and go for it.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Thu Jul 28, 2005 12:39 pm    Post subject: Re: typedef vs. class Reply with quote

Paul Rosen wrote:
Quote:
mzdude wrote:

[...]
hdr1.h
struct MyStuff {
// stuff
};
class StuffArray : public std::vector< MyStuff > {};

I can now do the following in hdr2.h

class StuffArray; // just a forward reference
void MyFunct( const StuffArray &sa );

I know that stl containers aren't designed to be base
classes, since they don't have virtual destructors, but in
this case I think it's OK. Are there any significant
drawbacks to the class declaration vs the typedef? In many
cases, by using the forward declaration, significant compile
time dependacies get reduced. I have checked this out with
several different versions of a compiler (not noted for it's
adherance to the standard) and it seems to function
correctly.

I did that a while back and it seems to work and it greatly
increases modularity. I asked a similar question to this list
and didn't get any concrete objections other than "The
standard says it's undefined, so you can't do it."

Where does the standard say it's undefined? The only thing that
is illegal is deleting an object through a pointer to the base
class; if all of his client code uses StuffArray, systematically
(including in the declarations of pointers), he should have no
problem.

Quote:
I personally can't think of a way for it to fail if you don't
define any data in StuffArray. The problem is to make sure
that code maintainers understand that, too. Adding a comment
might help that.

It has nothing to do with defining data or not. Since his
functions all require a StuffArray, and not the base class, his
clients should only use StuffArray, and not the std::vector. If
they do this systematically, then there is nothing illegal, and
the code is guaranteed by the standard to work.

Even if you add data to StuffArray at some later date.

If you want to be really safe, you'll inherit privately, then
use using to expose all of the functions in the interface.

Quote:
I have also yielded to temptation and done the following:

class StuffArray : public std::vector< MyStuff
{
public:
std::vector< MyStuff >::iterator CoolAlgorithm() const { ... };
};

Again, being careful not to define data. In this case, it is
more likely that the next guy is going to not realize that.

Again, what does defining data have to do with it?

Quote:
The only coding difference I've seen has something to do with
implicit conversions. I forget the example, but one place in
my code didn't compile because there would have been two
implicit conversions.

The rule is only one *user defined* implicit convertion. The
derived to base is not a user defined convertion, so it
shouldn't enter into account here.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
tony_in_da_uk@yahoo.co.uk
Guest





PostPosted: Thu Jul 28, 2005 3:12 pm    Post subject: Re: typedef vs. class Reply with quote

HI mzdude,

Personally, I think it's a terrible thing to do. This type of "class
X;" forward declaration has all the problems of embedding "extern void
fn();" statements in implementation files. It quickly leads to
unmaintainable code, as the code doesn't break when then real header
changes, and errors notification is delayed to link or run time.

What if the implementer changes StuffArray's type? Your makefiles
won't trigger a recompile, your "class X" won't get updated, and you
may get a run-time crash. If X changes to a typedef again, your link
will break.

If you're concerned about your build times, follow the example of
<iosfwd> and create a fwd-declaration-header with declarations
sufficient for pointers and references to your types, and include that
from both the existing header and your client code. Some projects use
a separate extension or naming for such headers: .hh, .fwd.h etc..

Tony


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
mzdude
Guest





PostPosted: Thu Jul 28, 2005 3:15 pm    Post subject: Re: typedef vs. class Reply with quote

Somehow sprinkling typedefs all over the code seems ... wrong. Too
many years of single definitions to overcome for me to embrace that
particular solution. I did think about a separate header file but
rejected it for the following reason. It increases coupling, which is
what I'm trying to avoid. By putting *all* or most of my typedefs in a
single header file any time one is added, deleted or modified, every
file that includes the common typedef header file will have to be
recompiled, even though the change will not effect most of them.

Our application is split in several dll's (less than 10). A small
change that requires releasing all of them tends to make users
nervous. Not to mention it freaks out the Q/A guys. They like to see a
change limited to 1 or at most 2.

I agree that typedefs tend to stabilize fairly quickly in development.
I would like to find a *style* that can be used for projects that are
new, in development and mature.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
mzdude
Guest





PostPosted: Fri Jul 29, 2005 12:49 am    Post subject: Re: typedef vs. class Reply with quote

Changing the type *will* force a recompile. Any changes to
MyArrayDef.h file will force the appropriate files to recompile. The
..cpp file that includes the header will realize the change, and
recompile. That's the point. Only the .cpp's effected will recompile.

MyArrayDef.h
struct MyStruct {
//
};
class MyArray : public std::vector< MyStruct > {};

Myfile.h
class MyArray; // forward ref
viod MyFunction( const class MyArray & );

MyFile.cpp
#include "MyFile.h"
#include "MyArrayDef.h" // definition of MyArray required for
file to compile

void MyFunction( const class MyArray &ma )
{
// do good stuff with ma
}


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Dave Harris
Guest





PostPosted: Fri Jul 29, 2005 12:52 am    Post subject: Re: typedef vs. class Reply with quote

[email]jsanga (AT) cox (DOT) net[/email] (mzdude) wrote (abridged):
Quote:
particular solution. I did think about a separate header file but
rejected it for the following reason. It increases coupling, which is
what I'm trying to avoid. By putting *all* or most of my typedefs in a
single header file any time one is added, deleted or modified, every
file that includes the common typedef header file will have to be
recompiled, even though the change will not effect most of them.

You can use one header per typedef. For example, you can have a header
called "Hdr1_forward.h" which contains all forward declarations for
Hdr1.h. It will be much smaller and more stable than Hdr1.h. I have used
this approach in a few crucial cases.


Quote:
Our application is split in several dll's (less than 10).

I don't think that's relevant here. If the definition of StuffArray is
changed, every DLL which uses it needs to be recompiled. It doesn't matter
whether the change is propagated by #includes or by copy&paste.

-- Dave Harris, Nottingham, UK.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Dave Harris
Guest





PostPosted: Fri Jul 29, 2005 1:01 am    Post subject: Re: typedef vs. class Reply with quote

[email]prosen (AT) fte (DOT) com[/email] (Paul Rosen) wrote (abridged):
Quote:
class StuffArray : public std::vector< MyStuff
{
public:
std::vector< MyStuff >::iterator CoolAlgorithm() const { ... };
};

This raises an additional issue, namely that any members of vector will be
visible in CoolAlgorithm(). I think it's even possible that std::vector
has a virtual private member called CoolAlgorithm(); if so, calling it
would now invoke your code unexpectedly.

If you are going this route - and it's a good idea to add member functions
- best practice is usually to make the vector a member variable and
provide forwarding functions and typedef's.

class StuffArray
{
typedef std::vector< MyStuff > Base;
Base base;
public:
typedef base::iterator iterator;

iterator push_back( const MyStuff &s ) {
return base.push_back( s );
}

iterator CoolAlgorithm() const { ... }
};

The forwarding functions are a pain to write, but you only have to provide
the ones that clients need. The more member functions like CoolAlgorithm
you add, the fewer forwarding functions are needed by clients.

Failing that, use private inheritance and using-declarations.

class StuffArray : private std::vector< MyStuff > Base
{
typedef std::vector< MyStuff > Base;
public:
typedef base::iterator iterator;

using Base::push_back;

iterator CoolAlgorithm() const { ... }
};

It is still worth adding the typedef's.

-- Dave Harris, Nottingham, UK.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Dave Harris
Guest





PostPosted: Fri Jul 29, 2005 1:03 am    Post subject: Re: typedef vs. class Reply with quote

[email]greghe (AT) pacbell (DOT) net[/email] (Greg) wrote (abridged):
Quote:
In this situation I would just copy StuffArray's typedef into hdr2.h

That's what I do too:

struct MyStuff;
typedef std::vector<MyStuff> StuffArray;

Note that technically you should not instantiate std::vector on an
incomplete class. I am fairly sure that the typedef does not trigger an
implicit instantiation.

I am less sure about uses of the typedef. Eg:

void MyFunct1( const StuffArray &sa );
void MyFunct2( StuffArray sa );
void MyFunct3( const StuffArray &sa ) { MyFunct1(sa); }
void MyFunct4( stuffArray sa ) { MyFunct2(sa); }

I'd like to think MyFunct1 and MyFunct2 did not instantiate the vector,
and hopefully MyFunct3 doesn't either, but I find the rules on implicit
instantiation of templates impossibly arcane.


Quote:
And there is little danger of ending up with typedefs for the same
name disagreeing, since the first file that includes both versions
will catch the error.

Indeed. And I make a point of ensuring the header which duplicates the
definition also #includes the real one it the corresponding source file,
so there is always a compile-time consistency check.

A variation is to make the typedef a member:

class MyClass {
public:
typedef std::vector<MyStuff> StuffArray;
void MyFunc( StuffArray & );
};

This eliminates the problem with the one-definition rule.

-- Dave Harris, Nottingham, UK.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
tony_in_da_uk@yahoo.co.uk
Guest





PostPosted: Fri Jul 29, 2005 12:47 pm    Post subject: Re: typedef vs. class Reply with quote

Say the programmer who supports MyArrayDef changes the type of MyArray
in MyArrayDef.h. In a large system, they're unlikely to know about all
the client code that uses their class, and will have to assume that
these client systems will detect the change to the header and recompile
if necessary.

Your MyFile.cpp example is safe: and as long as other programs using
MyFile.o proactively trigger MyFile's makefile, which is an entirely
reasonable assumption (if all-too-often overlooked in corporate
systems).

But there are other, more subtle, issues. For example:

- Lib.h declares a traits template and wants traits for MyArray. To
avoid including MyArrayDef.h, it embeds a forward declaration "class
MyArray;". There's nothing keeping these traits in sync with
MyArrayDef.h. Run-time errors result.

- Say a facility stores a pointer to an application-wide "active"
MyArray, which it forward declares. This facility doesn't need to
include MyArrayDef.h anywhere, so it continues to compile unchanged
even if the real MyArray is moved into another namespace, or becomes a
typedef. Only when a client program eventually goes to use the
facility will someone become aware that there's a compilation issue,
and the facility is out of sync. This means the library maintainers
are being reactive rather than proactive in maintaining a working
facility for their clients.

If I had half an hour, I could probably think of better examples, but
at least this establishes that there are some....

Tony


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.