Avoid including header file by declaring class. But what for typedef???

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • nguillot

    Avoid including header file by declaring class. But what for typedef???

    Hello.

    If I have the following classes:

    class B {};
    typedef B tB;

    if A is:

    class A
    {
    void f(B* pB) {}
    };

    in the header where A is defined, I can write
    class B;
    to avoid including the header file declaring B.

    But what for typedef:

    if A is:

    class A
    {
    void f(tB* pB) {}
    };

    if I write
    class tB;
    in A.h, I have the follwing compiler error:
    error C2371: 'tB' : redefinition; different basic types, because a
    typedef is not a class.

    I tried several syntax, but finally, is it possible to declare a
    typedef like we do for a class?

    Thanks for help.
  • Salt_Peter

    #2
    Re: Avoid including header file by declaring class. But what fortypedef ???

    On Aug 20, 9:50 am, nguillot <nicolas.guil.. .@gmail.comwrot e:
    Hello.
    >
    If I have the following classes:
    >
    class B {};
    typedef B tB;
    >
    if A is:
    >
    class A
    {
    void f(B* pB) {}
    >
    };
    >
    in the header where A is defined, I can write
    class B;
    to avoid including the header file declaring B.
    No, you definitely want to include that header.
    Thats what include guards are for.
    >
    But what for typedef:
    >
    if A is:
    >
    class A
    {
    void f(tB* pB) {}
    >
    };
    >
    if I write
    class tB;
    in A.h, I have the follwing compiler error:
    error C2371: 'tB' : redefinition; different basic types, because a
    typedef is not a class.
    >
    I tried several syntax, but finally, is it possible to declare a
    typedef like we do for a class?
    >
    Thanks for help.

    First off, use a const reference or a reference instead of a pointer.
    Typedef's are not neccessarily usefull.
    If you don't show compileable code, we can only guess at your problem.
    Guessing is bad, very bad.
    Use include guards, as follows:

    // A.h
    #ifndef A_H_
    #define A_H_

    #include <iostream>
    #include "B.h"

    class A
    {
    public:
    void f(const tB& rb)
    {
    std::cout << "n = ";
    std::cout << rb.get();
    std::cout << std::endl;
    }
    };

    #endif

    // B.h
    #ifndef B_H_
    #define B_H_

    class B
    {
    int n;
    public:
    B() : n(99) { }
    int get() const { return n; }
    };

    typedef B tB; // ugly

    #endif

    // test.cpp
    #include "A.h"

    int main()
    {
    A a;
    tB b;
    a.f( b );
    }

    Comment

    • tony_in_da_uk@yahoo.co.uk

      #3
      Re: Avoid including header file by declaring class. But what fortypedef ???

      On Aug 20, 10:50 pm, nguillot <nicolas.guil.. .@gmail.comwrot e:
      [snip] I can write
      class B;
      to avoid including the header file declaring B.
      You can but you shouldn't, despite lots of generally respected authors
      recommending it.

      If the developer of the header declaring B thinks including the header
      imposes (or may one day impose) a significant performance penalty,
      they should provide a forward-declaration header (e.g. <iosfwd>
      instead of <iostream>). If they haven't provided such a header, and
      you can't talk them into doing so, and you're working on a non-trivial
      project with many source files using their header, then you can create
      and maintain a single forward-declaration header yourself. Still
      painful, but at least centralised.

      Declaring things that the B-developer is quite entitled to change at
      any time (e.g. from a class to a typedef to a template instantiation)
      is as bad as the olden-days habit of not using headers, and having
      extern declarations for the extra-translation-unit functions you plan
      to call....

      To make the most of your build tools (e.g. make), you have to work in
      with their logic about recompilation, not fight it with hacks.
      Changes with compatible usage should trigger a rebuild.

      Cheers,
      Tony

      Comment

      • Greg Herlihy

        #4
        Re: Avoid including header file by declaring class. But what fortypedef ???

        On Aug 20, 6:50 am, nguillot <nicolas.guil.. .@gmail.comwrot e:
        >
        If I have the following classes:
        >
        class B {};
        typedef B tB;
        >
        if A is:
        >
        class A
        {
        void f(B* pB) {}
        };
        >
        in the header where A is defined, I can write
        class B;
        to avoid including the header file declaring B.
        >
        But what for typedef:
        >
        if A is:
        >
        class A
        {
        void f(tB* pB) {}
        };
        >
        if I write
        class tB;
        in A.h, I have the follwing compiler error:
        error C2371: 'tB' : redefinition; different basic types, because a
        typedef is not a class.
        >
        I tried several syntax, but finally, is it possible to declare a
        typedef like we do for a class?
        Yes, by redeclaring the tB typedef in A.h:

        // A.h

        class B;

        typedef B tB;

        Greg

        Comment

        • Jorgen Grahn

          #5
          Re: Avoid including header file by declaring class. But what for typedef ???

          On Wed, 20 Aug 2008 12:48:03 -0700 (PDT), tony_in_da_uk@y ahoo.co.uk <tony_in_da_uk@ yahoo.co.ukwrot e:
          On Aug 20, 10:50 pm, nguillot <nicolas.guil.. .@gmail.comwrot e:
          >[snip] I can write
          >class B;
          >to avoid including the header file declaring B.
          >
          You can but you shouldn't, despite lots of generally respected authors
          recommending it.
          ....
          Declaring things that the B-developer is quite entitled to change at
          any time (e.g. from a class to a typedef to a template instantiation)
          is as bad as the olden-days habit of not using headers, and having
          extern declarations for the extra-translation-unit functions you plan
          to call....
          Unlike that old pain, a "class B;" in my code cannot silently cause my
          program to stop working, can it?
          To make the most of your build tools (e.g. make), you have to work in
          with their logic about recompilation, not fight it with hacks.
          Changes with compatible usage should trigger a rebuild.
          I take it that is your main argument against forward declarations.

          I disagree, at least in the case where I am the author of class B and
          can change both B and the code which uses it whenever needed.
          Bringing down compilation times is worth a lot, in my opinion. I also
          prefer my code seeing as few names as possible, even if everything is
          in namespaces and there are no macros with too generic names.

          To answer the original question a bit: I think the problem he sees
          with typedefs is a reason many people prefer not to typedef classes.

          /Jorgen

          --
          // Jorgen Grahn <grahn@ Ph'nglui mglw'nafh Cthulhu
          \X/ snipabacken.se R'lyeh wgah'nagl fhtagn!

          Comment

          • Puppet_Sock

            #6
            Re: Avoid including header file by declaring class. But what fortypedef ???

            On Aug 20, 9:50 am, nguillot <nicolas.guil.. .@gmail.comwrot e:
            Hello.
            >
            If I have the following classes:
            >
            class B {};
            typedef B tB;
            >
            if A is:
            >
            class A
            {
                void f(B* pB) {}
            >
            };
            >
            in the header where A is defined, I can write
            class B;
            to avoid including the header file declaring B.
            >
            But what for typedef:
            >
            if A is:
            >
            class A
            {
                void f(tB* pB) {}
            >
            };
            >
            if I write
            class tB;
            in A.h, I have the follwing compiler error:
            error C2371: 'tB' : redefinition; different basic types, because a
            typedef is not a class.
            >
            I tried several syntax, but finally, is it possible to declare a
            typedef like we do for a class?
            Well... You say theerror is in A.h. But, I'md doubting it.
            I'm thinking the error is actually in some .CPP file that
            includes the A.h header.

            This would seem to indicate that some .CPP file includes both
            A.h and B.h.

            As others have said, you want to resist this scheme.
            If you absolutely need it, can't do without it, then...

            So what to do about that? Well, clearly what you need is
            some kind of include guard. Getting down to the level of
            individual typedefs is, maybe, a little finicky.

            But as somebody suggested, you want a Bfwd, or forward
            defn header. And it gets its own include guards. If you
            have control of both B.h and A.h then you can have B.h
            include Bfwd.h for the typedef, and that way make sure
            it is identical in both B.h and A.h.

            And that gets you past the gnarly possible things that
            might happen if the class B changes.
            Socks

            Comment

            • nguillot

              #7
              Re: Avoid including header file by declaring class. But what fortypedef ???

              Thanks for all your answers.

              To answer to some comments:

              I don't see why typedef B tB; is ugly.
              If B is std::map<std::s tring, std::.....the typedef is worth.
              With the typedef I can write tB::iterator, instead of
              std::map<std::s tring, std::.....>::it erator.
              And it factorizes the code.

              About providing compileable code, so you only can guess... Do you
              really think it's a problem.
              I guess the problem was explain (and the problem is not about pointer
              or reference), it's about including header or forwarding declarations;
              and how to forward the declaration of a typedef. Not more about
              protecting header with the guard #ifdef...
              But sorry if my question was not clear.

              My main question was indeed (but I learned the correct vocabulary by
              reading your answers):
              how to forward declare a typedef.

              About using headers instead of forward declaration, I guess it's a
              real debate. Good authors defend one way or the other.

              For my problem, I would need this forward declaration to decrease the
              compilation time (really decrease!).
              A.h as B.h are my code, I have access to it.

              So because it's really worth to decrease compilation time, the
              solution would to provide a forward header... I'll try that way.

              Thanks a lot for your answers.

              Comment

              • tony_in_da_uk@yahoo.co.uk

                #8
                Re: Avoid including header file by declaring class. But what fortypedef ???

                On Aug 22, 1:30 am, Jorgen Grahn <grahn+n...@sni pabacken.sewrot e:
                Unlike [embedded extern fn declarations], a "class B;" in my code
                cannot silently cause my program to stop working, can it?
                Depends who you are in the software system, what you call silently and
                working, and what expectations and responsibilitie s you feel different
                developers involved can have of and to each other.

                As a library developer defining a class X in a header, I would argue
                that you are entitled to replace it with "template <typename Tclass
                XT {...}; typedef XT<intX;", as well-written client code that
                includes your header will seamlessly recompile and work. This is
                standard practice when evolving code is generalised to arbitrary
                types.

                But - silently from the perspective of the library developer who
                doesn't necessarily know about all client usage or trigger client app
                recompilation - poorly-written client code hard-coding "class X;" will
                break. Scenario: Some production issue requires a urgent bug fix and
                instead the app developer finds unrelated parts of their app aren't
                compiling any more and must be fixed simultaneously, delaying
                deployment of the fix. If the library developer considers their
                clients as part of their overall "system" (a responsible attitude and
                generally expected in corporate life at least), then yes their change
                broke their system. But they're not really to blame....

                Can it be worse? Probably. Thinking about all the combinations of
                layers of objects, headers, static vs load-time vs run-time binding
                etc. does my head in and I'd need a better reason for suffering that
                than this thread.

                About the best that can be said is that at least some of these issues
                differ from extern function abuses, where the consequences are more
                consistently in the SIGSEGV category ;-).
                To make the most of your build tools (e.g. make), you have to work in
                with their logic about recompilation, not fight it with hacks.
                Changes with compatible usage should trigger a rebuild.
                >
                I take it that is your main argument against forward declarations.
                >
                I disagree, at least in the case where I am the author of class B and
                can change both B and the code which uses it whenever needed.
                Bringing down compilation times is worth a lot, in my opinion. I also
                prefer my code seeing as few names as possible, even if everything is
                in namespaces and there are no macros with too generic names.
                Forward declaration headers - maintained by the downstream library -
                are the only proper way to handle this. If a header pulls in myriad
                other headers AND has many independent parts then it's a strong
                candidate for separation into multiple headers / forward-declaration
                pairs, with the original header including the parts. This way
                upstream clients can select those parts that are useful without the
                full burden of including extra headers. pImpl / envelope-letter
                idioms help. If managed maturely, the compilation times can almost
                always be kept thoroughly under control and don't begin to justify the
                complications of the "class X;" hack.

                Tony

                Comment

                • Jorgen Grahn

                  #9
                  Re: Avoid including header file by declaring class. But what for typedef ???

                  (A very late response)

                  On Fri, 22 Aug 2008 01:57:26 -0700 (PDT), tony_in_da_uk@y ahoo.co.uk <tony_in_da_uk@ yahoo.co.ukwrot e:
                  On Aug 22, 1:30 am, Jorgen Grahn <grahn+n...@sni pabacken.sewrot e:
                  >Unlike [embedded extern fn declarations], a "class B;" in my code
                  >cannot silently cause my program to stop working, can it?
                  >
                  Depends who you are in the software system, what you call silently and
                  working, and what expectations and responsibilitie s you feel different
                  developers involved can have of and to each other.
                  >
                  As a library developer defining a class X in a header [...]
                  You are probably right about the library case, but I do not think it
                  is so common that it should dictate general practice.

                  My basic assumption was that I was *not* a library developer, i.e.
                  that I personally link the final executable, or a close co-worker
                  does. Or put more in configuration management terms, that we deliver
                  executables, and noone delivers inputs to us, except well-tested and
                  stable 3rd-party libraries.

                  In that scenario, I can save a lot of work and uncertainty by making
                  assumptions about the code (and I can refactor any part of it until
                  the assumptions hold).

                  And I also believe lots of bad code has been written because it was
                  needlessly written as if it was a library. I *still* see classes
                  where a lot of work is spent on unused features: "virtual" for classes
                  which noone inherits from, copy constructors and operator= for classes
                  which noone copies, function arguments with default values which noone
                  ever provides ...

                  /Jorgen

                  --
                  // Jorgen Grahn <grahn@ Ph'nglui mglw'nafh Cthulhu
                  \X/ snipabacken.se R'lyeh wgah'nagl fhtagn!

                  Comment

                  Working...