casting abstract classes

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • kostocka
    New Member
    • Mar 2007
    • 5

    casting abstract classes

    Dear gurus,

    I have been reading about polymorphism and generally think that I get the idea. At least I've gotten some code to work. Now I'm trying to get a little fancier and can't seem to figure out the following dilemma.

    I have an abstract class Base, and some Derived classes:

    Code:
    class Base {
    public:
    	void f1 () {
                  //....
            }
    	
      	virtual void f2() = 0;
    };
    
    class Derived1 {
    public:
            Derived1(int p1, int p2) {
                  //...
            }
      	void f2() {
                  //...
            }
    };
    
    class Derived2 {
    public:
            Derived2(int p1, int p2) {
                  //...
            }
      	void f2() {
            //...
            }
    };
    Until recently, I was happy with just declaring a derived class and using it:

    Code:
    void someFunc(Base var);
    
    int main(int argc, char *argv[]) {
         Derived var(p1, p2);
    
         someFunc(var);
         return 0;
    }
    Now, what I really want is to be able to decide at runtime what class type to use. I can't pre-declare it either because I have pure virtual functions (e.g. f2) in my Base class. I tried making them non-pure (just empty) and then assigning like this:

    Code:
    void someFunc(Base var);
    
    int main(int argc, char *argv[]) {
         Base var;
         if (arg[1] == 0) {
               Derived1 v(p1, p2);
               var = v;
         } else {
               Derived2 v(p1, p2);
               var = v;
         }
    
         someFunc(var);
         return 0;
    }
    It compiled fine, but the program clearly does not work right. So now I'm realizing that I'm missing some concepts here and need help.
    Thanks in advance
  • gpraghuram
    Recognized Expert Top Contributor
    • Mar 2007
    • 1275

    #2
    Originally posted by kostocka
    Dear gurus,

    I have been reading about polymorphism and generally think that I get the idea. At least I've gotten some code to work. Now I'm trying to get a little fancier and can't seem to figure out the following dilemma.

    I have an abstract class Base, and some Derived classes:

    Code:
    class Base {
    public:
    	void f1 () {
                  //....
            }
    	
      	virtual void f2() = 0;
    };
    
    class Derived1 {
    public:
            Derived1(int p1, int p2) {
                  //...
            }
      	void f2() {
                  //...
            }
    };
    
    class Derived2 {
    public:
            Derived2(int p1, int p2) {
                  //...
            }
      	void f2() {
            //...
            }
    };
    Until recently, I was happy with just declaring a derived class and using it:

    Code:
    void someFunc(Base var);
    
    int main(int argc, char *argv[]) {
         Derived var(p1, p2);
    
         someFunc(var);
         return 0;
    }
    Now, what I really want is to be able to decide at runtime what class type to use. I can't pre-declare it either because I have pure virtual functions (e.g. f2) in my Base class. I tried making them non-pure (just empty) and then assigning like this:

    Code:
    void someFunc(Base var);
    
    int main(int argc, char *argv[]) {
         Base var;
         if (arg[1] == 0) {
               Derived1 v(p1, p2);
               var = v;
         } else {
               Derived2 v(p1, p2);
               var = v;
         }
    
         someFunc(var);
         return 0;
    }
    It compiled fine, but the program clearly does not work right. So now I'm realizing that I'm missing some concepts here and need help.
    Thanks in advance
    You are speaking about polymorphism and you haven't used virtual or inherited from base class.

    Raghuram

    Comment

    • weaknessforcats
      Recognized Expert Expert
      • Mar 2007
      • 9214

      #3
      You are close.


      What you do at runtime is create a Derived object.

      Then assign the address of this object to a Base pointer.

      Your example shows assignment to a Base object and this is incorrect. When you assign to a Base object, the Derived object is sliced so that the Derived part is cut off. Bad news. In C++ polymorphism only works when you use a Derived object through a Base* otr a Base&.

      Next, since a Derived object is being used as a Base object, then it is important to call a Derived method instead of a Base method when this Derived object is used as a Base* or Base&. This is where the virtual function comes in.

      Try to example again, only this time use a Base* to represent your Derived object.

      Comment

      • kostocka
        New Member
        • Mar 2007
        • 5

        #4
        Originally posted by gpraghuram
        You are speaking about polymorphism and you haven't used virtual or inherited from base class.

        Raghuram
        yes, sorry, I meant to write:

        Code:
        class Derived1 : public Base {
        
        }
        class Derived2 : public Base {
        
        }

        Comment

        • kostocka
          New Member
          • Mar 2007
          • 5

          #5
          Originally posted by weaknessforcats
          You are close.


          What you do at runtime is create a Derived object.

          Then assign the address of this object to a Base pointer.

          Your example shows assignment to a Base object and this is incorrect. When you assign to a Base object, the Derived object is sliced so that the Derived part is cut off. Bad news. In C++ polymorphism only works when you use a Derived object through a Base* otr a Base&.

          Next, since a Derived object is being used as a Base object, then it is important to call a Derived method instead of a Base method when this Derived object is used as a Base* or Base&. This is where the virtual function comes in.

          Try to example again, only this time use a Base* to represent your Derived object.
          Thanks! The pointer did the trick (mostly). The following works as expected:
          Code:
          #include <stdio.h>
          #include <stdlib.h>
          #include <iostream>
          #include <string>
          
          using namespace std;
          
          class Base {
          public:
          //   string temp;
            virtual void whoami() = 0;
          };
          
          class Derived1 : public Base {
          public:
            virtual void whoami() {
              cout << "== Derived1 ==" << endl;
            }	
          };
          
          class Derived2 : public Base {
          public:
            virtual void whoami() {
              cout << "== Derived2 ==" << endl;
            }
          };
          
          int main(int argc, char *argv[]) {
            int t = 0;
            Base * var;
          
            if (t == 1) {
              Derived1 v;
              var = &v;
              var->whoami();
            } else if (t == 0) {
              Derived2 v;
              var = &v;
              var->whoami();
            }
            var->whoami();
          
            return 0;
          }
          The only problem I have left is if I uncomment the string temp declaration in line 10, The program crashes with the following message:

          Code:
          == Derived2 ==
          pure virtual method called
          terminate called without an active exception
          Abort
          I am working with a much bigger code base in reality and it took me a while to isolate the issue to that seemingly innocent declaration. I am starting to think that this is a compiler issue. Does anyone have any clues? I am using gcc version 4.1.2

          Thanks.

          Comment

          • weaknessforcats
            Recognized Expert Expert
            • Mar 2007
            • 9214

            #6
            If t is not 0 or 1 you will call var->whoami() when it is still an uninitialized Base*.

            Ka-Boom!

            Comment

            • kostocka
              New Member
              • Mar 2007
              • 5

              #7
              Originally posted by weaknessforcats
              If t is not 0 or 1 you will call var->whoami() when it is still an uninitialized Base*.

              Ka-Boom!
              yes, I realize that. I'm omitting some safety checks to keep the example short. Clearly, t is initialized here, it goes Ka-Boom anyway, but only if I uncomment line 10.

              Comment

              • weaknessforcats
                Recognized Expert Expert
                • Mar 2007
                • 9214

                #8
                Well I uncommented line 10 (string temp), compiled and executed this using Visual Studio.NET 2005 and it did not Ka-Boom.

                Is the code in your Post #5 the exact code that crashes??

                Comment

                • kostocka
                  New Member
                  • Mar 2007
                  • 5

                  #9
                  Originally posted by weaknessforcats
                  Well I uncommented line 10 (string temp), compiled and executed this using Visual Studio.NET 2005 and it did not Ka-Boom.

                  Is the code in your Post #5 the exact code that crashes??
                  yes, it is. What is even more weird is that if I declare 'int temp' instead, it works fine. I finally got everything to work by declaring 'new Derived'. If someone can explain to me why this makes sense, that would be great, otherwise the thread can be considered closed. Here is the working code in case somebody else cares:

                  Code:
                  class Base {
                    string temp;
                  public:
                    virtual void whoami() = 0;
                  };
                  
                  class Derived1 : public Base {
                  public:
                    virtual void whoami() {
                      cout << "== Derived1 ==" << endl;
                    }	
                  };
                  
                  class Derived2 : public Base {
                  public:
                    virtual void whoami() {
                      cout << "== Derived2 ==" << endl;
                    }
                  };
                  
                  int main(int argc, char *argv[]) {
                    int t = 0;
                    Base * var;
                  
                    if (t == 1) {
                      //Derived1 v;
                      //var = &v;
                      var = new Derived1;
                      var->whoami();
                    } else if (t == 0) {
                      //Derived2 v;
                      //var = &v;
                      var = new Derived2;
                      var->whoami();
                    }
                    var->whoami();
                  
                    return 0;
                  }

                  Comment

                  • weaknessforcats
                    Recognized Expert Expert
                    • Mar 2007
                    • 9214

                    #10
                    Your crash is here:
                    [code=cpp]
                    if (t == 1) {
                    Derived1 v;
                    var = &v;
                    var->whoami();
                    } else if (t == 0) {
                    Derived2 v;
                    var = &v; <<<<<<<<<<<<<<< <<<<<<<<<<
                    var->whoami();
                    }
                    var->whoami(); <<<<<<<<<<KA-BOOM!
                    [/code]

                    The Derived2 object goes out of scope at the end of the if statement. But you still use the object after it has gone out of scope.

                    This is the old: A function can never return an address or a reference to a local variable.

                    Comment

                    Working...