Trying to downcast a class stored in vector from a function

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • neisan
    New Member
    • Feb 2008
    • 4

    Trying to downcast a class stored in vector from a function

    Hi,

    I created a vector like that" typedef std::vector<Cli ent*> Clients" and declared a vector "Clients clients". I specialized the Client class to SpecialClient, so I have:

    Code:
      class Client
      {
      public:
        /// Constructor
        Client (void); 
        /// Destructor
        virtual ~Client (void);
        /// Register the client
        virtual void show_info (char* name) ;
        /// Get the name.
        void  set_name (const char * name);
      private:
        std:string name;
    }
    
    
      class SpecialClient
      {
      public:
        /// Constructor
        SpecialClient (void); 
        /// Destructor
        virtual ~SpecialClient (void);
        /// Register the client
        virtual void show_info (char* name) ;
        /// Get the details.
        void  set_details (const* char details);
      private:
        std:string details;
    }
    I declared the vector as
    Code:
    typedef std::vector<Client*> Clients;
    Clients clients;
    So I can store Client, SpecialClient and any other derived type of Client that I may need in the future.

    My function populates the "clients" vector and return it to a calling program. So I have:

    Code:
    SpecialClient* cl = new SpecialClient();
    cl->set_name("Client1");
    cl->set_details("Details client 1");
    clients.push_back(cl);
    The function returns:
    Code:
      Clients obtain_clients () {
        return (clients);
    }
    In the main function I try to cast the vector elements to SpecialClient but it's not working correct.

    Code:
    Clients cls = obtain_clients();
    int index;
    for(index=0; index < cls.size(); index++) {
      Client* cl = (cls.at(index));
      std::string name = cl->get_name();
      std::cout << "Name: " << name << std::endl;
      SpecialClient * scl = dynamic_cast<SpecialClient*>(cl);
      std::string details = scl->get_details();
      std::cout << "Details: " << details << std::endl;
    }
    What happens is that the "name" is printed correctly but the "details" not. The cast occurs fine but the contect of the details member is not printed. I guess I'm missing some memory allocation but I can't figure out the problem. I'll appreciatte if you can help me.

    Thank you.

    Nei
  • weaknessforcats
    Recognized Expert Expert
    • Mar 2007
    • 9214

    #2
    First, stop casting.

    Second, SpecialClient does not inherit from Client. SO this code:
    Originally posted by neisan
    SpecialClient* cl = new SpecialClient() ;
    cl->set_name("Clie nt1");
    cl->set_details("D etails client 1");
    can't compile since SpecialClient does not have a set_name() method.

    How are you getting this to run at all?

    Comment

    • neisan
      New Member
      • Feb 2008
      • 4

      #3
      Sorry,

      My mistake, I have:

      Code:
        class SpecialClient:Client
       {
        public:
          /// Constructor
          SpecialClient (void); 
          /// Destructor
          virtual ~SpecialClient (void);
          /// Register the client
          virtual void show_info (char* name) ;
          /// Get the details.
          void  set_details (const* char details);
        private:
          std:string details;
        }
      What do you mean with stop casting? I have a vector that stores pointers to Client objects and need to access the SpecialClient members.

      Thank you.

      Comment

      • weaknessforcats
        Recognized Expert Expert
        • Mar 2007
        • 9214

        #4
        Originally posted by neisan
        What do you mean with stop casting? I have a vector that stores pointers to Client objects and need to access the SpecialClient members.
        I mean stop casting.

        If you have a SpecialClient object you can use its address as a Client address:
        [code=cpp]
        SpecialClient* s = new SpecialClient
        vector<Client*> clients;
        clients.push_ba ck(s);
        [/code]

        No cast. A SpecialClient IS-A Client. Therefore, a SpecialClient pointer is a pointer to a Client.

        Then when you:
        [code=cpp]
        Client* cl = (cls.at(index)) ;
        [/code]

        and what you fetch is really a SpecialClass pointer then this code:
        [code=cpp]
        std::string name = cl->get_name();
        [/code]
        calls the get_name() of the Client object that is part of the SpecialClass object.

        But this:
        [code=cpp]
        std::string details = scl->get_details( ); //ERROR
        [/code]

        will never work since get_details is not a Client method.

        The fundamental error here is that the interface is not fully defined in the Client base class. The cast is a hack to cover a design flaw.

        You cannot add methods to a derived class and expect to call them using a base class.

        The best solution is to properly design Client so all methods are in the Client.

        You might also research separating the interface from the implementation. This will lead you to start using private virtual functions. Public virtual functions are a design no-no. That's because the clas should hide its implemenatation and a public function exposes it thereby breaking encapsulation.

        Comment

        • neisan
          New Member
          • Feb 2008
          • 4

          #5
          Hi,

          Thank you for your help. After putting all the code in one file and compiling it I realized that the problem I’m having is not because of the downcast. The problem is that I’m not being able to correct return the character and string values in the code. I’m sorry if I made you spend your time but I really appreciate the advices and information you provided. I’m trying now to solve the string manipulation problem.

          Thank you again.

          Nei


          Originally posted by weaknessforcats
          I mean stop casting.

          If you have a SpecialClient object you can use its address as a Client address:
          [code=cpp]
          SpecialClient* s = new SpecialClient
          vector<Client*> clients;
          clients.push_ba ck(s);
          [/code]

          No cast. A SpecialClient IS-A Client. Therefore, a SpecialClient pointer is a pointer to a Client.

          Then when you:
          [code=cpp]
          Client* cl = (cls.at(index)) ;
          [/code]

          and what you fetch is really a SpecialClass pointer then this code:
          [code=cpp]
          std::string name = cl->get_name();
          [/code]
          calls the get_name() of the Client object that is part of the SpecialClass object.

          But this:
          [code=cpp]
          std::string details = scl->get_details( ); //ERROR
          [/code]

          will never work since get_details is not a Client method.

          The fundamental error here is that the interface is not fully defined in the Client base class. The cast is a hack to cover a design flaw.

          You cannot add methods to a derived class and expect to call them using a base class.

          The best solution is to properly design Client so all methods are in the Client.

          You might also research separating the interface from the implementation. This will lead you to start using private virtual functions. Public virtual functions are a design no-no. That's because the clas should hide its implemenatation and a public function exposes it thereby breaking encapsulation.

          Comment

          Working...