Thread: Help Needed: Abstract Classes and Object Creation and Access

  1. #1
    Registered User deadpoet's Avatar
    Join Date
    Jan 2004
    Posts
    50

    Question Help Needed: Abstract Classes and Object Creation and Access

    To all,

    I will try to keep this scenario simple. I want to try to create a class having the following design:
    Code:
                                **************
                                **  Animal  **
                                ** Abstract **
                                **************
                                      |
                                      |
                                **************
                                ** Species  **
                                **   Base   **
                                **************
                                    /    \
                                   /      \
                        **************  **************
                        **    Dog   **  **    Cat   **
                        **************  **************
    My thoughts are that everything sould be created in terms of an animal where the Animal class should be able to create other Species that are of type Dog and Cat. Dog and Cat should have the ability to access properties (methods and data types) from species. But I currently can only figure out how to create Dogs abd Cats from Species having NO access to Species data types. What am I doing wrong?

    I have provided some sample code as to what I am doing. The Cat class has been removed to shorten the listing however it is the same code as Dog (just change Dog to Cat).

    main.cc
    Code:
    #include "animal.h"
    #include "species.h"
    int main() {
      Species species1( new Cat, new Dog );
      species1.print();
      return ( EXIT_SUCCESS );
    }
    animal.h
    Code:
    #ifndef _ANIMAL_H_
    #define _ANIMAL_H_
    #include <iostream.h>
    #include <string>
    #include <cstdlib>
    class Animal {
     public:
        Animal() {}
        virtual void print( void ) = 0;
        virtual string get_name( void ) = 0;
    };
    #endif
    species.cc
    Code:
    #include "species.h"
    Species::Species( Animal *pG ) {
        pCat = 0;
        pDog = 0;
        pGeneric = pG;
        name = "SPARKY";   //  <---- To simulate some type of data type needed by Dog and Cat.
    }
    Species::Species( Animal *pC, Animal *pD ){
        pCat = pC;
        pDog = pD;
        pGeneric = 0;
        name = "SPARKY";
    }
    void Species::print( void ){
        cout << "Name=" << name << endl;
        if ( pCat != 0 ) { pCat->print(); }
        if ( pDog != 0 ) { pDog->print(); }
        if ( pGeneric != 0 ) { pGeneric->print(); }
    }
    Species::~Species(){
        if ( pCat ) { delete pCat; }
        if ( pDog ) { delete pDog; }
        if ( pGeneric ) { delete pGeneric; }
    }
    string Species::get_name ( void ) {  // <--- To simulate some type of method needed by Dog and Cat.
      return ( name );
    }
    species.h
    Code:
    #include "animal.h"
    #include "cat.h"
    #include "dog.h"
    class Species {
     public:
        string name;
        // Constructor(s)
        Species( Animal *pG );
        Species( Animal *pC, Animal *pD );
    
        virtual void print( void );
        string get_name ( void );
    
        // Destructor
        ~Species();
     private:
        Animal *pGeneric, *pCat, *pDog;
    };
    #endif
    dog.cc
    Code:
    #include "dog.h"
    Dog::Dog(){
        color = "brown";
    }
    Dog::Dog( string s ){
        color = s;
    }
    Dog::~Dog(){
    }
    void Dog::print( void ){
        cout << "Dog = " << color << endl;
        cout << "Dog Name = " << get_name() << endl;
    }
    string Dog::get_name( void ) {
      string s = "UNKNOWN";
      //string s = Species::get_name();   // <--- I would have expected some thing like this but it is WRONG!
      return ( s );
    }
    dog.h
    Code:
    #ifndef _DOG_H_
    #define _DOG_H_
    #include "animal.h"
    #include "species.h"   // <--- I would have expected some thing like this.
    class  Dog : public Animal {
     public:
        string color;
    
        Dog();
        Dog( string s );
        ~Dog();
        void print( void );
        string get_name( void );
    };
    #endif
    Code:
    The Code for cat.cc and cat.h is the same as dog.cc and doh.h.
    Thanks to any and all that respond.

    DeadPoet

  2. #2
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    Is something like this what you were trying for?
    Code:
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    class Animal {
    public:
      virtual string name() = 0;
      virtual ~Animal() {};
    };
    
    class Species: public Animal {
    public:
      Species ( string name_init )
        : my_name ( name_init )
      { cout<<"Making a Species\n"; }
      ~Species() { cout<<"Destroying a Species\n"; }
      string name() { return my_name; }
    private:
      string my_name;
    };
    
    class Dog: public Species {
    public:
      Dog()
        : Species ( "Dog" )
      { cout<<"Making a Dog\n"; }
      ~Dog() { cout<<"Destroying a Dog\n"; }
    };
    
    class Cat: public Species {
    public:
      Cat()
        : Species ( "Cat" )
      { cout<<"Making a Cat\n"; }
      ~Cat() { cout<<"Destroying a Cat\n"; }
    };
    
    int main()
    {
      Animal *dog1 = new Dog();
      Animal *cat1 = new Cat();
      Species *dog2 = new Dog();
      Species *cat2 = new Cat();
      Dog *dog3 = new Dog();
      Cat *cat3 = new Cat();
    
      cout<< dog1->name() <<endl;
      cout<< cat1->name() <<endl;
      cout<< dog2->name() <<endl;
      cout<< cat2->name() <<endl;
      cout<< dog3->name() <<endl;
      cout<< cat3->name() <<endl;
    
      delete cat3;
      delete dog3;
      delete cat2;
      delete dog2;
      delete cat1;
      delete dog1;
    }
    >But I currently can only figure out how to create Dogs abd Cats from Species having NO access to Species data types.
    You don't want access to Species data types. If your derived classes need access to data members of a base class, use a protected member function and inherit that as an interface.

    I'm not too keen on your choice of having pDog and pCat in your Species class. That rather restricts you when it comes to adding new Species. You would have to make major changes to the Species class just to add another derived class. That's bad design.

    And your hierarchy diagram doesn't match your inheritance structure.
    My best code is written with the delete key.

  3. #3
    Registered User deadpoet's Avatar
    Join Date
    Jan 2004
    Posts
    50
    Prelude,

    I am not sure that this will cover the scenario. Let me place the scenario into the contex that I am working with and try to add some rational thought.

    If we take the Animal scenario and change it to a hardware scanner that I am working on for HP-UX it might look like the following:

    Code:
                                  ******************
                                  **  CInventory  **
                                  **   Abstract   **
                                  ******************
                                          |
                                          |
                                **********************
                                **  CObjectCreator  **
                                **       Base       **
                                **********************
                                        /    \
                                       /      \
                        ******************  *******************
                        **   CStorage   **  **    CNetwork   **
                        ******************  *******************
    Now assume that the CStorage and CNetwork Objects contain all the installed devices of that type contained on a given system. Thus is a complete object representing all the physical properties of each storage device or network device contained in a nicely indexed map container. Because of the way some of the internals for the operating system work, I am forced to lstat the device directory, once for the CStorage and once for the CNetwork Object because I need to map the device file name to a major and minor number. This is not bad when you look at the way most UNIX commands work but I know that I should be able to perform this operation at a higher level and reduce it down to just one lstat that all the lower objects have access to. So I would think that if either the CInventory or the CObjectCreator could provide this functionality I should be able to access this information from the lower levels. I would also think that main would look something like:
    Code:
    CInventory *ptrCI = new CObjectCreator( new CStorge(), new CNetwork() );
    Maybe, I am just not seeing the big picture. Any help would be of great assistance.

    Thanks,

    DeadPoet

  4. #4
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    It sounds as if CInventory and CObjectCreator are wrappers. They contain the CStorage and CNetwork objects and simplify operations on them by doing two things with one function call. Something more like this:
    Code:
    class CInventory;
    class CStorage;
    class CNetwork;
    class CObjectCreator: public CInventory {
    public:
      ...
      lstat();
    private:
      ...
      CStorage storage;
      CNetwork network;
    };
    Or perhaps a more organized approach with multiple inheritance:
    Code:
    class CDevice;
    class CStorage: public CDevice;
    class CNetwork: public CDevice;
    class CInventory: public CStorage, public CNetwork;
    class CObjectCreator {
    private:
      CInventory devices;
    };
    My best code is written with the delete key.

  5. #5
    Registered User deadpoet's Avatar
    Join Date
    Jan 2004
    Posts
    50
    Yes, the multiple inheritance concept is what I am going for. Do I have the instantiation from main correct?
    Code:
    CInventory *ptrCI = new CDevice( new CStorge(), new CNetwork() );
    Finally, does this approach make sense to you and are you adding an additional class into the hierarchy?

    Code:
                                  ******************
                                  **  CInventory  **
                                  **   Abstract   **
                                  ******************
                                          |
                                          |
                                   ***************
                                   **  CDevice  **
                                   **    Base   **
                                   ***************
                                        /    \
                                       /      \
                        ******************  *******************
                        **   CStorage   **  **    CNetwork   **
                        ******************  *******************
    Thanks in advance for all the assistance,

    DeadPoet
    Last edited by deadpoet; 03-10-2004 at 11:09 AM.

  6. #6
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >Do I have the instantiation from main correct?
    If you're following the diagram you give later then no. CStorage and CNetwork are specializations of CDevice. Having a base class contain objects of its own child classes is rather strange considering your abstraction. Think of it this way: A CDevice is an inventory (CDeviceInventory might be a better name). A CStorage is an inventory of storage devices. A CNetwork is an inventory of network devices. That is as far as the abstraction goes. Now you want to have a container that gives you stats for both a storage inventory and a network inventory. You do this with another class:
    Code:
    class InventoryStat {
      ...
    private:
      CStorage storage;
      CNetwork network;
    };
    Then you could reasonably instantiate from main like so:
    Code:
    InventoryStat is ( new CStorage(), new CNetwork() );
    Another alternative I already showed you is to specialize CStorage and CNetwork into an InventoryStat with multiple inheritance. Then your diagram would look like this:
    Code:
                                  ******************
                                  **  CInventory  **
                                  **   Abstract   **
                                  ******************
                                          |
                                          |
                                   ***************
                                   **  CDevice  **
                                   **    Base   **
                                   ***************
                                        /    \
                                       /      \
                        ******************  *******************
                        **   CStorage   **  **    CNetwork   **
                        ******************  *******************
                                   \             /
                                    \           /
                                 ********************
                                 ** CInventoryStat **
                                 ********************
    But with this approach your instantiation would be more like so:
    Code:
    CInventoryStat is;
    Because CInventoryStat already has CStorage and CNetwork as a part of it.

    >Finally, does this approach make sense to you?
    Provided CDevice is logically a CInventory, yes.
    My best code is written with the delete key.

  7. #7
    Registered User deadpoet's Avatar
    Join Date
    Jan 2004
    Posts
    50
    Let me work with the information that you have provided. I think you have a solid grasp of what I am trying to accomplish and I am sure that I will have additional questions but I must think about the problem before I ask any more questions. Thanks for all your help.

    DeadPoet

  8. #8
    Registered User deadpoet's Avatar
    Join Date
    Jan 2004
    Posts
    50
    After re-reading your post, I wanted to clairify one aspect.

    Having a base class contain objects of its own child classes is rather strange considering your abstraction.
    My thought behind having the CInventory class as abstract is to provide the ability to expand the code as follows:

    Code:
                                ******************
                                **  CInventory  **
                                **   Abstract   **
                                ******************
                                /                \
                               /                  \
                ***************                    ***************
                **  CDevice  **                    **  CConfig  **
                **   Base    **                    **   Base    **
                ***************                    ***************
                    /    \                             /      \
                   /      \                           /        \
    ******************  *******************    *************  ***************
    **   CStorage   **  **    CNetwork   **    ** CKernel **  ** CSoftware **
    ******************  *******************    *************  ***************
              \             /
               \           /
            ********************
            ** CInventoryStat **
            ********************
    Does this make sense? I am open to any suggestions. It must just remain scalable because of enhancement requests.

    DeadPoet

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. OOP Question DB Access Wrapper Classes
    By digioz in forum C# Programming
    Replies: 2
    Last Post: 09-07-2008, 04:30 PM
  2. Creating a database
    By Shamino in forum Game Programming
    Replies: 19
    Last Post: 06-10-2007, 01:09 PM
  3. Mmk, I give up, lets try your way. (Resource Management)
    By Shamino in forum Game Programming
    Replies: 31
    Last Post: 01-18-2006, 09:54 AM
  4. structure vs class
    By sana in forum C++ Programming
    Replies: 13
    Last Post: 12-02-2002, 07:18 AM
  5. Inheiritance and derived classes
    By pecymanski in forum C++ Programming
    Replies: 2
    Last Post: 12-09-2001, 03:50 PM