It is currently Tue Oct 17, 2017 2:42 am

All times are UTC - 5 hours




 Page 1 of 1 [ 11 posts ] 
Author Message
 Post subject: Working with classes Dynamically
PostPosted: Wed Nov 16, 2011 8:25 am 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 449
The objective that I am trying to implement is I want to create a class object that takes in an int parameter
that has to be >= 0. If the value is <= 0 then it will be clamped to 0 and no object will be created. This part is easy enough. I am using explicit constructor here, but what I would like to do is for the value that is passed in
I want that class itself to dynamicaly create that many object pointers and store it into its own std::vector
These classes will be inherited too.
#ifndef OBJ_H
#define OBJ_H

#include "base.h"

class Obj : public Base {
public:
     int _iNumObj;
private:
     int  _id;
     static int _counter;
     std::vector<Obj*> _vObj;

public:
     explicit Obj( int iNumObjects = 1 ); // Defualted to one, if Obj() is called only 1 obj will be created
    ~Obj();
   
     int    getID() { return _id; } 
     std::vector<Obj*> getPointers() { return _vObj; }
private:
     Obj( const Obj &o );
     Obj& operator=( const Obj &e );
}; // Obj

#endif


Above is a sample class header. How would I setup the constructors to create the amount passed into its constructor, create a pointer to it and save this pointer into our member vector? The _id number needs to be updated as well, and stay current with the number that is created. For example: Obj obj(3); the third object to be created will have an _id of 3 etc.
So if i was to access the vector from a return function:

#include "stdafx.h"
#include "Obj.h"

int main() {

     Obj obj(3);

     std::vector<Obj*> vLocal;
     vLocal = obj.getPointers();

     // then I should be able to do something like:
     int a,b,c;
     a = vLocal[0]->getID()  // a should = 1;
     b = vLocal[1]->getID()  // b should = 2;
     c = vLocal[2]->getID()  // c should = 3;
     
     printf( "The IDs are #%d #%d #%d, a, b, c );

     return 0;

} // main


Last edited by skilz80 on Wed Nov 16, 2011 6:21 pm, edited 1 time in total.

Offline
 Profile  
 
 Post subject: Re: Working with classes Dynamically
PostPosted: Wed Nov 16, 2011 5:04 pm 
Site Admin

Joined: Sun Feb 11, 2007 8:59 am
Posts: 1105
Location: Ontario Canada
Why is your Class Obj trying to create copies of itself and store it in the vector? Are you trying to create a tree/node structure?

I can see this making more sense if your root class object was something different and it contained "Obj" objects. As it is defined right now, you'll have an infinte loop of objects being created as soon as you try to put something into your vector.


Offline
 Profile  
 
 Post subject: Re: Working with classes Dynamically
PostPosted: Wed Nov 16, 2011 5:22 pm 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 449
Ok here is the basic idea. I have A base class and from it another base class. the second base class has 3 other classes belonging to it. I was wondering if it is possible to pass into the inherited class the amount of objects of this type you want to create. Or should I not bother and whatever other class is using this object should be responsible for. I will send you a copy of my source code class for you to look at. With a little more description of what I am looking for.


Offline
 Profile  
 
 Post subject: Re: Working with classes Dynamically
PostPosted: Wed Nov 16, 2011 7:53 pm 
Site Admin

Joined: Sun Feb 11, 2007 8:59 am
Posts: 1105
Location: Ontario Canada
Since you are inheriting from Base and you intend to inherit from Obj as well make sure that both of these classes have virtual destructors. Otherwise you are opening the door for memory leaks.

Have a read through the difference between Object Composition: http://en.wikipedia.org/wiki/Compositio ... rogramming

and inheritance: http://en.wikipedia.org/wiki/Inheritanc ... rogramming)

It sounds like you are getting them confused.


Offline
 Profile  
 
 Post subject: Re: Working with classes Dynamically
PostPosted: Wed Nov 16, 2011 8:03 pm 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 449
base i am inheriting from where obj i am not

the example I show'd here would be compared to

Electron : public Particle {
};

where Electron is the one I was trying to create on the fly


Offline
 Profile  
 
 Post subject: Re: Working with classes Dynamically
PostPosted: Wed Nov 16, 2011 10:09 pm 
Site Admin

Joined: Sun Feb 11, 2007 8:59 am
Posts: 1105
Location: Ontario Canada
skilz80 wrote:
...where Electron is the one I was trying to create on the fly


Okay, why do you want an Electron class containing a vector of Electrons?


Offline
 Profile  
 
 Post subject: Re: Working with classes Dynamically
PostPosted: Wed Nov 16, 2011 10:42 pm 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 449
It is not so much that I am concerned with having a vector of pointers to this class. I was thinking on the lines
that if we were to call this classes constructor with a single value passed in either it be in int or an enumeration ID value, and what ever value is passed into this constructor. I wanted the constructor to create that many instances of its self and to end up saving the pointers into a vector.

example

somefile.cpp
#include "Electron.h"

someclass::somefunction() {
Electron e( 8 ); // or Electron e( OXYGEN );

// From this the constructor takes in the value of 8 and since 8 is the Element Oxygen which Has 8 Electrons
// The Idea Is To have the Electron's constructor go through a for loop or while loop through 8 iterations
// And at each iteration create an instance of this electron as well as a pointer to it. Then save the pointers
// Into a vector or array, for later access. Then down in the code such as

std::vector<Electron*> vE = e.getPointers(); // we would call the function since the member vector in e would be vE[i]->SomeMethod(); // private, save it to our local copy, then we can access it through indexing

}

so the Electrons constructor might look like this in theory

Electron::Electron( int iNumberElectronsToCreate ) {

for ( int i = 1; i <= iNumberElectronsToCreate; i++ ) {
Electron *pE = new Electron( iNumberElectronsToCreate - i );
if ( (!pE) || ((iNumberElectronsToCreate-i) < 1) ) {
delete pE;
return; // Not Enough Memory Or No More To Create
} else {
_vE.push_back( pE );
}
}
}

the destructor would be responsible for cleaning up the new memory and clearing the vector


Offline
 Profile  
 
 Post subject: Re: Working with classes Dynamically
PostPosted: Thu Nov 17, 2011 2:51 am 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 449
After working dilligently on this project. I went into a blank project and created a generic class to try and simulate, the concept I was working for and I found this to work like I want it to. The questions I have are:

1. What are the pitfalls for doing this. Considering that I am using the new operator, I just might make them smart pointers
instead of having to worry about manual clean up?
2. Is there a more efficient way to implement this?
3. Or would it be better to have some other arbitrary class that contains a pointer to it handle this process?
4. Probably the most important question is are their any memory leaks?

The code does work, and as far as I can think all you need to include is <vector>. I don't see any apparent bugs yet. If you happen to find any please let me know, I am always up to learning good coding ethics ^^;

class Test {

public:
   int _iNumberOfTests;  // How Many Objects We Want
private:
   static int _counter;

   
   int _id; // Our ID Value

   std::vector<Test*> _vTests;

public:
   explicit Test( int i = 0 );
   ~Test();


   void setPointers( std::vector<Test*> vT );
   std::vector<Test*> getPointers();
   void print();

private:
   Test( const Test &t );
   Test& operator=( const Test &T );

};

int Test::_counter = 0;

Test::Test( int iNum )
: _id( _counter++ ),
_iNumberOfTests( iNum ) {

   // Test To See If I Is >= 1 If Not Clamp It To 1
   /*if ( iNum < 1 ) {
      _iNumberOfTests = 1;
   }*/

   // Iterate Through A For Loop The Amount Of Times As The Value Passed In
   // Creating A New Pointer To An Instance Of This Class
   for ( int i = 1; i <= iNum; i++ ) {
      Test *t = new Test();
      // Check To See If Pointer Is Valid Or To See If The Equation iNum-1
      // Is < 0. Note That Creating 1 Is Allowed, And If 1 Is Passed In Or
      // The Constructor Is Called Without Any Parameters Setting The Parameter
      // To Its Default Value 1 Is The Max Number Of Iterations, And We See That
      // When We Start Our Loop i Is Equal To One And Since 1-1 = 0. Our Check Here
      // To See That We Completed Enough Iterations Is When iNum-i = 0 To Break Out
      // We Look To See When It Is Less Then 0. If So We Delete The Memory For t
      // And Return From Our Constructor Otherwise We Push This Pointer Onto Our
      // Member Variable std::vector of Test Pointers
      if ( (!t) || ((iNum-i) < 0) ) {
         delete t;
         return;
      } else {
         _vTests.push_back( t );
      }
   }
}
Test::Test( const Test &t )
: _id( ++_counter ), _iNumberOfTests( t._iNumberOfTests ) {


}
Test::~Test() {
   std::vector<Test*>::iterator it;
   for ( it = _vTests.begin(); it != _vTests.end(); ++it ) {
      delete (*it);
   }
   _vTests.clear();

}
void Test::setPointers( std::vector<Test*> vT ) {
   _vTests = vT;
}
std::vector<Test*> Test::getPointers() {
   return _vTests;
}
void Test::print() {
   printf( "Success! %d\n", _id );
}



int main()
{
    Test t(4);

   std::vector<Test*> vTest;
   
   
   vTest = t.getPointers();
   

   vTest[0]->print();
   vTest[1]->print();
   vTest[2]->print();
   vTest[3]->print();

   return 0;
}


Offline
 Profile  
 
 Post subject: Re: Working with classes Dynamically
PostPosted: Thu Nov 17, 2011 6:00 am 
Site Admin

Joined: Sun Feb 11, 2007 8:59 am
Posts: 1105
Location: Ontario Canada
When designing classes you should try to make them in such a way so that users of the class can't easily break what you are trying to create.

The way that the code is currently written someone could do this:
Test t;
std::vector<Test*> vT;

vT.push( null );
vT.push( null );
vT.push( null );

t.setPointers( vT );


Secondly, the copy constructor doesn't actually copy anything.... or at least it doesn't copy what your Test class contains!

Now you have a big mess to deal with! Things that I would change:
* Make your constructor private
* create a static function that is used to constructor your overall Electron class
* Fix the copy constructor
* delete the setPointers function or if you really need it, make it private
* getPointers returns a copy of your actual std::vector which is probably not what you want in the first place.

Based on what I understand of your requirements I'd make the class structure something like this:
Class Atom {
private:
  std::vector<Electron> _vElectrons;   
  std::vector<Proton> _vProtons;
  std::vector<Neutron> _vNeutrons;

public: 
   Atom( int elementName );

}


Offline
 Profile  
 
 Post subject: Re: Working with classes Dynamically
PostPosted: Thu Nov 17, 2011 9:43 am 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 449
Thank you for your feed back. I will probably rewrite it to match the second case.
I was just trying to see if a class could create x - amount of its self on construction by the value passed in.

It is not necessary for me to keep that way, It is more of a coding practice, to see how well written code vs
poor code. Always a great learning experience. Thank you for the advice.


Offline
 Profile  
 
 Post subject: Re: Working with classes Dynamically
PostPosted: Fri Nov 25, 2011 6:22 am 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 449
Ok now I am puzzled... I am working inside of a class that will dynamically create 4 different classes that are all inherited from one base class. I am going through a while loop and inside this while loop I am also going through a switchstatement. depending on the case will determine which of these classes will be created through function calls
and these function calls are returning a pointer that is a pointer to the base class. then I am trying to insert this into a map that has a count value, and a structure that has the id or level of the inherited class plus a pointer to the base class. When I try to build or compile I keep getting this error and MSDN doesn't do a good job about explaining how to fix it, only show a little bit about what is cause it. The error is C2512: no apporpriate default constructor. I will dislpay the .h and .cpp file below. The base and inherited class are as this Shell - Base, ShellS ShellP ShellD ShellF are inherited publicly from Shell.

ElectronCloud.h
#ifndef ELECTRON_CLOUD_H
#define ELECTRON_CLOUD_H

#include "ShellS.h"
#include "ShellP.h"
#include "ShellD.h"
#include "ShellF.h"

namespace Creator {

   class ElectronCloud {
   
   protected:
   private:
      unsigned int _uiNumElectrons;
      vector< Electron* > _vpElectrons;   

      static const int _maxSShells;
      static const int _maxPShells;
      static const int _maxDShells;
      static const int _maxFShells;

      EnergyLevel *_pEnergyLevel;   

      struct ShellOrdering {
         int iLevel;
         Shell* pShell;

         ShellOrdering( int _iLevel, Shell* _pShell ) {
            iLevel = _iLevel;
            pShell = _pShell;
         }
      };

      map< int, ShellOrdering > _mpShells;


   public:
      ElectronCloud( const Element element );
      ~ElectronCloud();
      
      bool SetupElectronVector();
      bool InitializeEnergyLevel( const Element element );
      bool CreateShells();

   protected:
   private:   
      void CleanUp();
      void DeleteAllElectrons();
      void DeleteAllShells();      

      Shell* CreateShellS();
      Shell* CreateShellP();
      Shell* CreateShellD();
      Shell* CreateShellF();

   }; // ElectronCloud


}; // Creator

#endif // ELECTRON_CLOUD_H


ElectronCloud.cpp
#include "stdafx.h"
#include "ElectronCloud.h"

const int ElectronCloud::_maxSShells = 7;
const int ElectronCloud::_maxPShells = 6;
const int ElectronCloud::_maxDShells = 4;
const int ElectronCloud::_maxFShells = 2;

// -----------------------------------------------------------------------
// ElectronCloud()
// Constructor
ElectronCloud::ElectronCloud( const Element element ) {

   if ( element < HYDROGEN ) {
      return;
   } else if ( element >= ELEMENT_LAST ) {
      return;
   }
   else {
      _uiNumElectrons = (unsigned int)element;
   }   

} // ElectronCloud

// -----------------------------------------------------------------------
// ~ElectronCloud()
// Descturtor
ElectronCloud::~ElectronCloud() {

   delete _pEnergyLevel;
   
   CleanUp();

} // ~ElectronCloud

// -----------------------------------------------------------------------
// SetupElectronVector
// Populate Our Electron Vector Using Our Atomic Number
// Defualt = No Ionization
bool ElectronCloud::SetupElectronVector() {
   
   unsigned int uiIndex = _uiNumElectrons;
   while ( uiIndex > 0 ) {
      Electron *pE = new Electron();
      if ( !pE ) {
         return false;
      } else {
         _vpElectrons.push_back( pE );
      }
      --uiIndex;
   }

   return true;

} // SetupElectronVector

// -----------------------------------------------------------------------
// CleanUp()
// Free All Memory Allocated
void ElectronCloud::CleanUp() {

   DeleteAllElectrons();
   DeleteAllShells();

} // CleanUp

// -----------------------------------------------------------------------
// DeleteAllElectrons()
// Free All Memory Allocated
void ElectronCloud::DeleteAllElectrons() {

   for ( int i = 0; i < (int)_vpElectrons.size(); i++ ) {
      delete _vpElectrons[i];
   }

   _vpElectrons.clear();
} // DeleteAllElectrons

// -----------------------------------------------------------------------
// DeleteAllShells()
// Free All Memory Allocated
void ElectronCloud::DeleteAllShells() {

   for ( int i = 0; i < (int)_mpShells.size(); i++ ) {
      delete _mpShells[i].pShell;
   }

   _mpShells.clear();

} // DeleteAllShells

// -----------------------------------------------------------------------
// InitializeEnergyLevel()
// Create An Instance Of Our Energy Level
bool ElectronCloud::InitializeEnergyLevel( const Element element ) {

   _pEnergyLevel = new EnergyLevel( element );
   if ( !_pEnergyLevel ) {
      return false;
   }
   return true;

} // InitializeEnergyLevel

// -----------------------------------------------------------------------
// CreateShellS()
// Dynamically Create ShellS And Return A Pointer
Shell* ElectronCloud::CreateShellS() {
   
   ShellS *pS;
   // Create S Shell, Add Orbital And Return Our Pointer Or Null
            pS = new ShellS();
   if ( !pS ) {
      return NULL;
   }
   
   if ( !pS->AddOrbitals() ) {
      delete pS;
      pS = NULL;
      return NULL;
   }
   return ((Shell*)pS);

} // CreateShellS

// -----------------------------------------------------------------------
// CreateShellP()
// Dynamically Create ShellP And Return A Pointer
Shell* ElectronCloud::CreateShellP() {
   
   ShellP *pP;
   pP = new ShellP();
   if ( !pP ) {
      return NULL;
   }
   
   if ( !pP->AddOrbitals() ) {
      delete pP;
      pP = NULL;
      return NULL;
   }
   return ((Shell*)pP);

} // CreateShellP

// -----------------------------------------------------------------------
// CreateShellD()
// Dynamically Create ShellD And Return A Pointer
Shell* ElectronCloud::CreateShellD() {
   
   ShellD *pD;
   pD = new ShellD();
   if ( !pD ) {
      return NULL;
   }
   
   if ( !pD->AddOrbitals() ) {
      delete pD;
      pD = NULL;
      return NULL;
   }

   return ((Shell*)pD);

} // CreateShellD

// -----------------------------------------------------------------------
// CreateShellF()
// Dynamically Create ShellF And Return A Pointer
Shell* ElectronCloud::CreateShellF() {

   ShellF *pF;
   pF = new ShellF();
   if ( !pF ) {
      return NULL;
   }
   
   if ( !pF->AddOrbitals() ) {
      delete pF;
      pF = NULL;
      return NULL;
   }
   return ((Shell*)pF);

} // CreateShellF

// -----------------------------------------------------------------------
// CreateShells()
// This Function Is The Heart Of This Class And Library
bool ElectronCloud::CreateShells() {

   // First We Need To Know What Our Highest Energy Level Is
   // As Well As What Block We Are In
   int iCurrentLevel = 1;    // This Is Our N value   
   int iMaxLevel = _pEnergyLevel->GetEnergyLevel();

   int iCurrentBlock = 0;    // This Is Our L Value
   int iMaxBlock = _pEnergyLevel->GetAtomicBlock();

   // Ml and Ms Are Handled In The Orbital Class Since They Deal With
   // The Sub-sub shells and electron spin

   // We Need To Go Through And Create Our Shells
   // For Each Level That Exists And Place It Into Our Map
   int iCount = 1;
   Shell *pShell;
   while ( iCurrentLevel <= iMaxLevel ) {
      
      switch ( iCurrentLevel )
      {
         case ENERGY_LEVEL_ONE:
         {
            pShell = CreateShellS();
            _mpShells.insert( make_pair( iCount, ShellOrdering( iCurrentLevel, pShell ) ) );
            iCount++;
            
            break;
         }
         case ENERGY_LEVEL_TWO:
         {
            pShell = CreateShellS();
            _mpShells.insert( make_pair( iCount, ShellOrdering( iCurrentLevel, pShell ) ) );
            iCount++;
            
            pShell = CreateShellP();
            _mpShells.insert( make_pair( iCount, ShellOrdering( iCurrentLevel, pShell ) ) );
            iCount++;
            
            break;            
         }
         case ENERGY_LEVEL_THREE:
         {   
            pShell = CreateShellS();
            _mpShells.insert( make_pair( iCount, ShellOrdering( iCurrentLevel, pShell ) ) );
            iCount++;
            
            pShell = CreateShellP();
            _mpShells.insert( make_pair( iCount, ShellOrdering( iCurrentLevel, pShell ) ) );
            iCount++;
            
            break;   
         }
         case ENERGY_LEVEL_FOUR:
         {
            pShell = CreateShellS();
            _mpShells.insert( make_pair( iCount, ShellOrdering( iCurrentLevel, pShell ) ) );
            iCount++;
            
            pShell = CreateShellD();
            _mpShells.insert( make_pair( iCount, ShellOrdering( iCurrentLevel-1, pShell ) ) );
            iCount++;
            
            pShell = CreateShellP();
            _mpShells.insert( make_pair( iCount, ShellOrdering( iCurrentLevel, pShell ) ) );
            iCount++;
            
            break;
         }
         case ENERGY_LEVEL_FIVE:
         {
            
            pShell = CreateShellS();
            _mpShells.insert( make_pair( iCount, ShellOrdering( iCurrentLevel, pShell ) ) );
            iCount++;
            
            pShell = CreateShellD();
            _mpShells.insert( make_pair( iCount, ShellOrdering( iCurrentLevel-1, pShell ) ) );
            iCount++;
            
            pShell = CreateShellP();
            _mpShells.insert( make_pair( iCount, ShellOrdering( iCurrentLevel, pShell ) ) );
            iCount++;
            
            break;
         }
         case ENERGY_LEVEL_SIX:
         {
            pShell = CreateShellS();
            _mpShells.insert( make_pair( iCount, ShellOrdering( iCurrentLevel, pShell ) ) );
            iCount++;

            pShell = CreateShellF();
            _mpShells.insert( make_pair( iCount, ShellOrdering( iCurrentLevel-2, pShell ) ) );
            iCount++;
            
            pShell = CreateShellD();
            _mpShells.insert( make_pair( iCount, ShellOrdering( iCurrentLevel-1, pShell ) ) );
            iCount++;
            
            pShell = CreateShellF();
            _mpShells.insert( make_pair( iCount, ShellOrdering( iCurrentLevel, pShell ) ) );
            iCount++;
            
            break;
         }
         case ENERGY_LEVEL_SEVEN:
         {
            pShell = CreateShellS();
            _mpShells.insert( make_pair( iCount, ShellOrdering( iCurrentLevel, pShell ) ) );
            iCount++;

            pShell = CreateShellF();
            _mpShells.insert( make_pair( iCount, ShellOrdering( iCurrentLevel-2, pShell ) ) );
            iCount++;
            
            pShell = CreateShellD();
            _mpShells.insert( make_pair( iCount, ShellOrdering( iCurrentLevel-1, pShell ) ) );
            iCount++;
            
            pShell = CreateShellF();
            _mpShells.insert( make_pair( iCount, ShellOrdering( iCurrentLevel, pShell ) ) );
            iCount++;
            
            break;
         }
            
      } // switch

      iCurrentLevel++;
   } // while

   // If We Reached This Point We Have Successfully Created Our Shells
   return true;

} // CreateShells


The only functions of importance here is CreateShells, CreateShellS-F the structure ShellOrdering in the header file and the std map< int, ShellOrdering > _mpShells. I don't know why it is saying no default constructor and how to fix this.
if you need to see the Shell, ShellS-F classes .h and .cpp files let me know. Thank You.


Offline
 Profile  
 
Display posts from previous:  Sort by  
 Page 1 of 1 [ 11 posts ] 

All times are UTC - 5 hours


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Jump to:  

cron