Why can't I do this?

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

    Why can't I do this?

    Dear Gurus,

    This is a fairly simple question, but I can't figure out what the answer is.
    I can easily change my code, but I want to know why I can't do this to
    further my knowledge of the C++ language (and OO):

    class a
    {
    public:
    a(){ vm(); }
    virtual void vm() = 0;
    };

    class b : public a
    {
    public:
    void vm() { }
    };

    int main()
    {
    b B;

    return 0;
    }

    VC++ says: "error LNK2001: unresolved external symbol "public: virtual void
    __thiscall a::vm(void)"

    I understand that 'a' doesn't have a implementation of 'vm', but also I
    cannot create an instance of 'a' either (because it has a pure virtual
    function) so when I create a 'b' why can't 'a's constructor call 'b's 'vm'?

    Quentin.


  • Alf P. Steinbach

    #2
    Re: Why can't I do this?

    On Wed, 17 Sep 2003 22:46:09 GMT, "Quentin" <IHateSpam@Spam Sux.com> wrote:
    [color=blue]
    >This is a fairly simple question, but I can't figure out what the answer is.
    >I can easily change my code, but I want to know why I can't do this to
    >further my knowledge of the C++ language (and OO):
    >
    >class a
    >{
    > public:
    > a(){ vm(); }
    > virtual void vm() = 0;
    >};
    >
    >class b : public a
    >{
    > public:
    > void vm() { }
    >};
    >
    >int main()
    >{
    > b B;
    >
    > return 0;
    >}
    >
    >VC++ says: "error LNK2001: unresolved external symbol "public: virtual void
    >__thiscall a::vm(void)"
    >
    >I understand that 'a' doesn't have a implementation of 'vm', but also I
    >cannot create an instance of 'a' either (because it has a pure virtual
    >function) so when I create a 'b' why can't 'a's constructor call 'b's 'vm'?[/color]

    This is a FAQ.

    Look it up in the FAQ.

    If necessary, first look up where the FAQ is (Google, this group).


    Hth.,

    - Alf

    Comment

    • Quentin

      #3
      Re: Why can't I do this?

      > Look it up in the FAQ.

      Thanks Alf!

      Quentin.


      Comment

      • Marcin Vorbrodt

        #4
        Re: Why can't I do this?

        "Quentin" <IHateSpam@Spam Sux.com> wrote in message
        news:Ru5ab.1684 77$la.3499974@n ews1.calgary.sh aw.ca...[color=blue]
        > Dear Gurus,
        >
        > This is a fairly simple question, but I can't figure out what the answer[/color]
        is.[color=blue]
        > I can easily change my code, but I want to know why I can't do this to
        > further my knowledge of the C++ language (and OO):
        >
        > class a
        > {
        > public:
        > a(){ vm(); }
        > virtual void vm() = 0;
        > };
        >
        > class b : public a
        > {
        > public:
        > void vm() { }
        > };
        >
        > int main()
        > {
        > b B;
        >
        > return 0;
        > }
        >
        > VC++ says: "error LNK2001: unresolved external symbol "public: virtual[/color]
        void[color=blue]
        > __thiscall a::vm(void)"
        >
        > I understand that 'a' doesn't have a implementation of 'vm', but also I
        > cannot create an instance of 'a' either (because it has a pure virtual
        > function) so when I create a 'b' why can't 'a's constructor call 'b's[/color]
        'vm'?[color=blue]
        >
        > Quentin.
        >
        >[/color]

        Because at the time of construction of A part "this" pointer is still of
        type A, hence it does not know anything about B yet. In other words,
        construction starts at the top of inheritance tree, and the type of this
        pointer follows. BTW, Mayers in his book Effectife C++ has a chapter about
        this... you shouldn't (in most cases) call virtual functions from
        constructors.

        Martin


        Comment

        • Bill Thompson

          #5
          Re: Why can't I do this?

          "Quentin" <IHateSpam@Spam Sux.com> wrote in message
          news:Ru5ab.1684 77$la.3499974@n ews1.calgary.sh aw.ca...[color=blue]
          > Dear Gurus,
          >
          > This is a fairly simple question, but I can't figure out what the answer[/color]
          is.[color=blue]
          > I can easily change my code, but I want to know why I can't do this to
          > further my knowledge of the C++ language (and OO):
          >
          > class a
          > {
          > public:
          > a(){ vm(); }
          > virtual void vm() = 0;
          > };
          >
          > class b : public a
          > {
          > public:
          > void vm() { }
          > };
          >
          > int main()
          > {
          > b B;
          >
          > return 0;
          > }
          >
          > VC++ says: "error LNK2001: unresolved external symbol "public: virtual[/color]
          void[color=blue]
          > __thiscall a::vm(void)"
          >
          > I understand that 'a' doesn't have a implementation of 'vm', but also I
          > cannot create an instance of 'a' either (because it has a pure virtual
          > function) so when I create a 'b' why can't 'a's constructor call 'b's[/color]
          'vm'?[color=blue]
          >
          > Quentin.
          >
          >[/color]
          I'm by no means a guru, and of course you can check the FAQ, but I believe
          this is the problem:
          Class A is an abstract base class containing an unimplemented virtual
          function. Therefore, you cannot call vm() from the Class A constructor,
          because in Class A it doesn't exist.

          Call vm() from Class B's constructor.

          Think about it... why should the compiler allow you to call Class A's vm()
          if it has no function body? The compiler is doing you a favor here.

          An additional question: were you to derive additional classes from A, how
          would the compiler know which instance of vm() to call in A's constructor?



          Comment

          • jeffc

            #6
            Re: Why can't I do this?


            "Quentin" <IHateSpam@Spam Sux.com> wrote in message
            news:Ru5ab.1684 77$la.3499974@n ews1.calgary.sh aw.ca...[color=blue]
            > Dear Gurus,
            >
            > This is a fairly simple question, but I can't figure out what the answer[/color]
            is.[color=blue]
            > I can easily change my code, but I want to know why I can't do this to
            > further my knowledge of the C++ language (and OO):
            >
            > class a
            > {
            > public:
            > a(){ vm(); }
            > virtual void vm() = 0;
            > };
            >
            > class b : public a
            > {
            > public:
            > void vm() { }
            > };
            >
            > int main()
            > {
            > b B;
            >
            > return 0;
            > }
            >
            > VC++ says: "error LNK2001: unresolved external symbol "public: virtual[/color]
            void[color=blue]
            > __thiscall a::vm(void)"
            >
            > I understand that 'a' doesn't have a implementation of 'vm', but also I
            > cannot create an instance of 'a' either (because it has a pure virtual
            > function) so when I create a 'b' why can't 'a's constructor call 'b's[/color]
            'vm'?

            Whoa dude, you had it there for a minute. Now step back and think about
            what you're saying. Why would a base class EVER need to know anything about
            any of its subclasses? Inheritance doesn't work that way. When you create
            a b, b's constructor gets called, which means a's constructor is going to
            get called. But a base class function shouldn't call a subclass function.
            Once you're in code for a, all it sees is a.

            By the way, just because a is abstract doesn't mean you can't give a
            definition for the pure virtual function. It's a common mistake to think
            that though. It's often a useful technique to make a function pure virtual,
            but then provide a definition that the base classes can call from their
            overridden function, to do at least some common work. It might even be all
            that some subclasses need to do.


            Comment

            • jeffc

              #7
              Re: Why can't I do this?


              "jeffc" <nobody@nowhere .com> wrote in message
              news:3f69cf80_3 @news1.prserv.n et...[color=blue]
              > Whoa dude, you had it there for a minute. Now step back and think about
              > what you're saying. Why would a base class EVER need to know anything[/color]
              about[color=blue]
              > any of its subclasses? Inheritance doesn't work that way. When you[/color]
              create[color=blue]
              > a b, b's constructor gets called, which means a's constructor is going to
              > get called. But a base class function shouldn't call a subclass function.[/color]

              I was talking only about the constructor in this case, of course, not the
              general case of function overriding. Constructor time is different.


              Comment

              • Quentin

                #8
                Re: Why can't I do this?

                > Whoa dude, you had it there for a minute. Now step back and think about[color=blue]
                > what you're saying. Why would a base class EVER need to know anything[/color]
                about[color=blue]
                > any of its subclasses? Inheritance doesn't work that way. When you[/color]
                create[color=blue]
                > a b, b's constructor gets called, which means a's constructor is going to
                > get called. But a base class function shouldn't call a subclass function.
                > Once you're in code for a, all it sees is a.[/color]

                I get it now. Whoa dude :) hahaha!
                [color=blue]
                > By the way, just because a is abstract doesn't mean you can't give a
                > definition for the pure virtual function. It's a common mistake to think
                > that though. It's often a useful technique to make a function pure[/color]
                virtual,[color=blue]
                > but then provide a definition that the base classes can call from their
                > overridden function, to do at least some common work. It might even be[/color]
                all[color=blue]
                > that some subclasses need to do.[/color]

                Whoa dude, I did not know that! That could be very useful. Thanks for the
                tip!

                Quentin.


                Comment

                • Marcelo Pinto

                  #9
                  Re: Why can't I do this?

                  "Bill Thompson" <billt61@ixnayo ntheamspayrgv.r r.com> wrote in message news:<dm6ab.499 85$jV1.21688@tw ister.austin.rr .com>...[color=blue]
                  > "Quentin" <IHateSpam@Spam Sux.com> wrote in message
                  > I'm by no means a guru, and of course you can check the FAQ, but I believe
                  > this is the problem:
                  > Class A is an abstract base class containing an unimplemented virtual
                  > function. Therefore, you cannot call vm() from the Class A constructor,
                  > because in Class A it doesn't exist.
                  >
                  > Call vm() from Class B's constructor.
                  >
                  > Think about it... why should the compiler allow you to call Class A's vm()
                  > if it has no function body? The compiler is doing you a favor here.
                  >
                  > An additional question: were you to derive additional classes from A, how
                  > would the compiler know which instance of vm() to call in A's constructor?[/color]

                  Note that this is only true for calls in constructors. It's perfectly
                  valid to call an abstract function from any function except from
                  constructors and destructors (?).

                  BTW it is the central idea in the Template Method Pattern.

                  Regards,

                  Marcelo Pinto

                  Comment

                  • Bill Thompson

                    #10
                    Re: Why can't I do this?

                    "Marcelo Pinto" <mpinto@tecnoli nk.com.br> wrote in message
                    news:e3529d3b.0 309181230.719de 639@posting.goo gle.com...[color=blue]
                    > "Bill Thompson" <billt61@ixnayo ntheamspayrgv.r r.com> wrote in message[/color]
                    news:<dm6ab.499 85$jV1.21688@tw ister.austin.rr .com>...[color=blue][color=green]
                    > > "Quentin" <IHateSpam@Spam Sux.com> wrote in message
                    > > I'm by no means a guru, and of course you can check the FAQ, but I[/color][/color]
                    believe[color=blue][color=green]
                    > > this is the problem:
                    > > Class A is an abstract base class containing an unimplemented virtual
                    > > function. Therefore, you cannot call vm() from the Class A constructor,
                    > > because in Class A it doesn't exist.
                    > >
                    > > Call vm() from Class B's constructor.
                    > >
                    > > Think about it... why should the compiler allow you to call Class A's[/color][/color]
                    vm()[color=blue][color=green]
                    > > if it has no function body? The compiler is doing you a favor here.
                    > >
                    > > An additional question: were you to derive additional classes from A,[/color][/color]
                    how[color=blue][color=green]
                    > > would the compiler know which instance of vm() to call in A's[/color][/color]
                    constructor?[color=blue]
                    >
                    > Note that this is only true for calls in constructors. It's perfectly
                    > valid to call an abstract function from any function except from
                    > constructors and destructors (?).
                    >
                    > BTW it is the central idea in the Template Method Pattern.
                    >
                    > Regards,
                    >
                    > Marcelo Pinto[/color]

                    Yes, of course, after construction the vtable has been initialized. I
                    should have made it more obvious I was referring to constructors, not
                    calling virtual functions in general.


                    Comment

                    • jeffc

                      #11
                      Re: Why can't I do this?


                      "Quentin" <IHateSpam@Spam Sux.com> wrote in message
                      news:41mab.1746 44$la.3608396@n ews1.calgary.sh aw.ca...[color=blue]
                      >[color=green]
                      > > By the way, just because a is abstract doesn't mean you can't give a
                      > > definition for the pure virtual function. It's a common mistake to[/color][/color]
                      think[color=blue][color=green]
                      > > that though. It's often a useful technique to make a function pure[/color]
                      > virtual,[color=green]
                      > > but then provide a definition that the base classes can call from their
                      > > overridden function, to do at least some common work. It might even be[/color]
                      > all[color=green]
                      > > that some subclasses need to do.[/color]
                      >
                      > Whoa dude, I did not know that! That could be very useful. Thanks for[/color]
                      the[color=blue]
                      > tip![/color]

                      I had a typo - I meant "provide a definition that the *subclasses* can call
                      from their overridden function".

                      Example. Program for a football game. You have football players.

                      class FootballPlayer
                      class Punter : public FootballPlayer
                      class DefensiveEnd : public FootballPlayer

                      You don't have any players on the field that are so generic that you'd
                      create a FootballPlayer - everyone plays a specific position. Therefore,
                      you make FootballPlayer abstract. But in case of crazy plays, you want
                      every player on the field to be able to make a tackle. You might have a
                      pure virtual function called Tackle() which provides some basic tackling
                      technique.

                      class FootballPlayer
                      {
                      public:
                      void Tackle() = 0;
                      };

                      You might override Tackle() if there is some special technique defensive
                      players might use. But there's nothing wrong with defining
                      void FootballPlayer: :Tackle()
                      {
                      // tackle in some basic way
                      }

                      Then Punter could just do
                      void Punter::Tackle( )
                      {
                      FootballPlayer: :Tackle(); // the basic base function is good enough
                      }

                      The DefensiveEnd might add
                      void DefensiveEnd::T ackle()
                      {
                      FootballPlayer: :Tackle();
                      // plus add a harder hit, or trying to punch the ball away on the way down
                      }


                      Comment

                      • Christopher Benson-Manica

                        #12
                        Re: Why can't I do this?

                        jeffc <nobody@nowhere .com> spoke thus:
                        [color=blue]
                        > You don't have any players on the field that are so generic that you'd
                        > create a FootballPlayer - everyone plays a specific position. Therefore,
                        > you make FootballPlayer abstract. But in case of crazy plays, you want
                        > every player on the field to be able to make a tackle. You might have a
                        > pure virtual function called Tackle() which provides some basic tackling
                        > technique.[/color]
                        [color=blue]
                        > class FootballPlayer
                        > {
                        > public:
                        > void Tackle() = 0;
                        > };[/color]
                        [color=blue]
                        > You might override Tackle() if there is some special technique defensive
                        > players might use. But there's nothing wrong with defining
                        > void FootballPlayer: :Tackle()
                        > {
                        > // tackle in some basic way
                        > }[/color]
                        [color=blue]
                        > Then Punter could just do
                        > void Punter::Tackle( )
                        > {
                        > FootballPlayer: :Tackle(); // the basic base function is good enough
                        > }[/color]

                        Like football eh? ;) Seriously, I'm still a C++ newb, so I'm not seeing the
                        point of defining a pure virtual function and then overriding it. Why not
                        just make it a regular virtual function?

                        --
                        Christopher Benson-Manica | Jumonji giri, for honour.
                        ataru(at)cybers pace.org |

                        (blank space follows, sorry)































                        Comment

                        • Ron Natalie

                          #13
                          Re: Why can't I do this?


                          "Christophe r Benson-Manica" <ataru@nospam.c yberspace.org> wrote in message news:bkfm4l$mgl $2@chessie.cirr .com...[color=blue]
                          >
                          > Like football eh? ;) Seriously, I'm still a C++ newb, so I'm not seeing the
                          > point of defining a pure virtual function and then overriding it. Why not
                          > just make it a regular virtual function?
                          >[/color]
                          Why use function overloading, just give everything seperate names?
                          Because it makes sense to have the base class behavior impelemented
                          in a function of the same name, even if you're forced to think about
                          whether that is the proper behavior (by itself) in a derived class.


                          Comment

                          • Christopher Benson-Manica

                            #14
                            Re: Why can't I do this?

                            Ron Natalie <ron@sensor.com > spoke thus:
                            [color=blue]
                            > Why use function overloading, just give everything seperate names?
                            > Because it makes sense to have the base class behavior impelemented
                            > in a function of the same name, even if you're forced to think about
                            > whether that is the proper behavior (by itself) in a derived class.[/color]

                            M... (denseness/cluelessness alert!)

                            I thought the point of a pure virtual function was to force subclasses to
                            implement it, since the base class explicitly declines to do so. If the base
                            class wants to provide an implementation of a member function, what is
                            accomplished by declaring it to be purely virtual? Is it so a class that uses
                            classes derived from the base can choose to override the base virtual
                            function......?

                            --
                            Christopher Benson-Manica | Jumonji giri, for honour.
                            ataru(at)cybers pace.org |

                            Comment

                            • Ron Natalie

                              #15
                              Re: Why can't I do this?


                              "Christophe r Benson-Manica" <ataru@nospam.c yberspace.org> wrote in message news:bkfngu$mgl $4@chessie.cirr .com...[color=blue]
                              > Ron Natalie <ron@sensor.com > spoke thus:
                              >[color=green]
                              > > Why use function overloading, just give everything seperate names?
                              > > Because it makes sense to have the base class behavior impelemented
                              > > in a function of the same name, even if you're forced to think about
                              > > whether that is the proper behavior (by itself) in a derived class.[/color]
                              >
                              > M... (denseness/cluelessness alert!)
                              >
                              > I thought the point of a pure virtual function was to force subclasses to
                              > implement it, since the base class explicitly declines to do so.[/color]

                              The first part of your statement is true, the second isn't. It forces the
                              derived classes (at least those who are going to be concrete) to provide
                              an implementation, but it doesn't say boo about whether the base class
                              does or not.
                              [color=blue]
                              > If the base
                              > class wants to provide an implementation of a member function, what is
                              > accomplished by declaring it to be purely virtual?[/color]

                              We just told you, and the football example was provided. I'll give you a more real
                              world one right out of our main product. Inside we have a bunch of objects that
                              get passed around generically. They have various functions they implement
                              (including such common things as the relational operators, serialize output, etc...).
                              Lets take the serialize function. There is a default behavior of just writing an
                              encoded version of the object type (which there is obtainable from the base class
                              via another virtual function). However, that's NOT good enough for many of
                              the objects. Therefore, I make the base class method pure, so that it MUST
                              be overridden. This forces the derived class writer to make the decision between
                              using the default behavior or writing a different implementation. What it doesn't
                              allow (and we were screwed by this a couple of times before we did this) is
                              to forget to put an explicit statement of the proper behavior in his class definition.

                              [color=blue]
                              > Is it so a class that uses
                              > classes derived from the base can choose to override the base virtual
                              > function......?[/color]

                              Well a class can always chose to override the function. What it does is force
                              the derived class to make an explicit statement as to whether he wants the
                              base behavior or something else.


                              Comment

                              Working...