Copy constructor for class with vector of pointers

T

tech

Hi, I have developed a little class to help implement dynamic menus in
our
application which has a UI. This allows our engine to send a MenuItem
object to the UI which is an observer of the engine, then the UI can
construct
its menu based on the info in the object. The MenuItem is based on the
composite
design pattern so it contains a vector of child MenuItems, this allows
sub menus
to passed in aswell.

I currently don't know how to implement a copy constructor for this,
any ideas?
The vector won't contain any base class pointers to derived objects if
that
makes things easier. Second i read in Effective C++ not return handles
to
object internals which i seem to be doing in the :

const std::vector<MenuItem*>& SubMenuItems() const; method

I can't see how to get round this. Any other comments welcome.
Thanks


#include <string>
#include <vector>
#include <memory>


class MenuItem
{
public:
MenuItem();
MenuItem(std::wstring name, int id);
virtual ~MenuItem();

int Id() const;
std::wstring Name() const;
const std::vector<MenuItem*>& SubMenuItems() const;
void AddSubMenu(std::wstring name, int id);
bool SubMenuPresent() const;
typedef std::vector<MenuItem*> SubMenuItem;

private:
MenuItem(const MenuItem& item);
MenuItem& operator=(const MenuItem&);

private:
std::wstring m_itemName;
int m_id;
SubMenuItem m_subMenuItems;
};

MenuItem::MenuItem():m_itemName(L""),m_id(0)
{

}

MenuItem::MenuItem(std::wstring name, int
id):m_itemName(name),m_id(id)
{
}

MenuItem::~MenuItem()
{
// Iterate through all submenuitems

SubMenuItem::iterator it = m_subMenuItems.begin();
while ( it != m_subMenuItems.end() )
{
delete *it;
it = m_subMenuItems.erase(it);
}
}

int MenuItem::Id() const
{
return m_id;
}

std::wstring MenuItem::Name() const
{
return m_itemName;
}

const std::vector<MenuItem*>& MenuItem::SubMenuItems() const
{
return m_subMenuItems;
}

bool MenuItem::SubMenuPresent() const
{
return !m_subMenuItems.empty();
}

void MenuItem::AddSubMenu(std::wstring name, int id)
{
std::auto_ptr<MenuItem> item(new MenuItem(name, id));
m_subMenuItems.push_back(item.get());
item.release();
}


int main()
{
// Engine code would do this and pass the object to the UI
MenuItem item(L"File", 0);
item.AddSubMenu(L"New", 1);
item.AddSubMenu(L"Edit", 2);

// UI code would read the item object and construct menu
std::vector<MenuItem*>::const_iterator it =
item.SubMenuItems().begin();
while( it != item.SubMenuItems().end())
{
// Create submenu etc
++it;
}
return 0;
}
 
T

terminator

Hi, I have developed a little class to help implement dynamic menus in
our
application which has a UI. This allows our engine to send a MenuItem
object to the UI which is an observer of the engine, then the UI can
construct
its menu based on the info in the object. The MenuItem is based on the
composite
design pattern so it contains a vector of child MenuItems, this allows
sub menus
to passed in aswell.

I currently don't know how to implement a copy constructor for this,
any ideas?
The vector won't contain any base class pointers to derived objects if
that
makes things easier.

If you do not want base ptr to point to derived class objects (bad
idea)then you have got to to forget about runtime polymorphy (pointed
objects need not have virtual methods) in which case you can:

typedef std::vector<MenuItem> SubMenuItem;
......
SubMenuItem * m_subMenuItems;
......
const SubMenuItem& MenuItem::SubMenuItems() const
{
return *m_subMenuItems;
}



Second i read in Effective C++ not return handles
to
object internals which i seem to be doing in the :

const std::vector<MenuItem*>& SubMenuItems() const;     method

I can't see how to get round this. Any other comments welcome.
Thanks

let the MenuItem manage its own submenues by its own.use inheritance
for new types of menuitems derived from a basic one,use initializer
function objects:

template<typename func>
MenuItem::MenuItem(const func init){
init(m_subMenuItems);
};
....

void f(MenuItem::SubMenuItem & sm);

.....

MenuItem m (f);

and you can do a lot more than that.
#include <string>
#include <vector>
#include <memory>

        class MenuItem
        {
        public:
                MenuItem();
                MenuItem(std::wstring name, int id);
                virtual ~MenuItem();

                int Id() const;
                std::wstring Name() const;
                const std::vector<MenuItem*>& SubMenuItems() const;
                void AddSubMenu(std::wstring name, int id);
                bool SubMenuPresent() const;
                typedef std::vector<MenuItem*> SubMenuItem;

move the typedef to the top ; before the definition of member
functions:

typedef std::vector<MenuItem*> SubMenuItem;

int Id() const;
std::wstring Name() const;

and do not forget to use type name you have defined:

const SubMenuItem& SubMenuItems() const;
void AddSubMenu(std::wstring name, int id);
bool SubMenuPresent() const;
        private:
                MenuItem(const MenuItem& item);
                MenuItem& operator=(const MenuItem&);

        private:
                std::wstring m_itemName;
                int m_id;
                SubMenuItem m_subMenuItems;
        };

        MenuItem::MenuItem():m_itemName(L""),m_id(0)
        {

        }

        MenuItem::MenuItem(std::wstring name, int
id):m_itemName(name),m_id(id)
        {
        }

        MenuItem::~MenuItem()
        {
        // Iterate through all submenuitems

                SubMenuItem::iterator it = m_subMenuItems.begin();
                while ( it != m_subMenuItems.end() )
                {
                        delete *it;
                        it = m_subMenuItems.erase(it);
                }
        }

in case of using auto_ptr to objects:

typedef std::vector<std::auto_ptr<MenuItem> >
SubMenuItem;

you had better do not declare a destructor (compiler will generate a
proper one automaticall) or just define a trivial virtual destructor
that does not do anything.

But if you are using raw pointers :

typedef std::vector<MenuItem*> SubMenuItem;

then simply delete the allocated pointer and leave the rest to the
compiler:

MenuItem::~MenuItem()
{
// Iterate through all submenuitems
for(SubMenuItem::iterator it =
m_subMenuItems.begin();
it != m_subMenuItems.end();
++it)
{
delete *it;
}
}

        int MenuItem::Id() const
        {
                return m_id;
        }

        std::wstring MenuItem::Name() const
        {
                return m_itemName;
        }

        const std::vector<MenuItem*>& MenuItem::SubMenuItems() const

remember to use what you have defined:

const SubMenuItem & MenuItem::SubMenuItems() const
        {
                return m_subMenuItems;
        }

        bool MenuItem::SubMenuPresent() const
        {
                return !m_subMenuItems.empty();
        }

        void MenuItem::AddSubMenu(std::wstring name, int id)
        {
                std::auto_ptr<MenuItem> item(new MenuItem(name, id));
                m_subMenuItems.push_back(item.get());
                item.release();
        }

make up your mind use either raw pointers:


void MenuItem::AddSubMenu(std::wstring name, int id)
{
m_subMenuItems.push_back(new MenuItem(name, id));
}

or auto_ptr:

typedef std::vector<std::auto_ptr<MenuItem> >
SubMenuItem; typedef std::vector<MenuItem*>
SubMenuItem;
......

......

void MenuItem::AddSubMenu(std::wstring name, int id)
{
m_subMenuItems.push_back(new MenuItem(name, id));
}
int main()
{
    // Engine code would do this and pass the object to the UI
        MenuItem item(L"File", 0);
        item.AddSubMenu(L"New", 1);
        item.AddSubMenu(L"Edit", 2);

  // UI code would read the item object and construct menu
        std::vector<MenuItem*>::const_iterator it =
item.SubMenuItems().begin();
        while( it != item.SubMenuItems().end())
        {
                // Create submenu etc
according to the prototype of SubMenuItems() it returns a readonly
reference to an array ,hence you cannot modify its elements :that is
what const_iterator too implies.
you had better do submenu modifications inside class member
functions.
                ++it;
        }
        return 0;



}- Hide quoted text -

- Show quoted text -

In either case it seems that you have to provide a copy constructor
but the definition depends on how you 'typedef' the 'SubMenuItem'.
things are easy with raw pointers:

#include <algorithm>
....
typedef std::vector<MenuItem*> SubMenuItem;
MenuItem(const MenuItem& init) :
m_itemName(init.m_itemName),
m_id(init.mid))
{

m_subMenuItems.reserve(init.m_subMenuItems.size());/*this maybe
redundant but it is harmless*/

std::copy(m_subMenuItems.begin(),init.m_subMenuItems.begin(),init.m_subMenuItems.end());/
*i am in doubt about the order of parameters to function 'copy'.*/
}

with auto_ptr we face trouble because once an auto_ptr is copied the
source pointer will go null.

that`s all for now,
FM.
 
T

terminator

If you do not want base ptr to point to derived class objects (bad
idea)then you have got to to forget about runtime polymorphy (pointed
objects need not have virtual methods) in which case you can:

                typedef std::vector<MenuItem> SubMenuItem;
                ......
                SubMenuItem * m_subMenuItems;
                ......
        const SubMenuItem& MenuItem::SubMenuItems() const
        {
                return *m_subMenuItems;
        }




let the MenuItem manage its own submenues by its own.use inheritance
for new types of menuitems derived from a basic one,use initializer
function objects:

   template<typename func>
    MenuItem::MenuItem(const func init){
       init(m_subMenuItems);
   };
   ....

  void f(MenuItem::SubMenuItem & sm);

   .....

   MenuItem m (f);

and you can do a lot more than that.










move the typedef to the top ; before the definition of member
functions:

                typedef std::vector<MenuItem*> SubMenuItem;

                int Id() const;
                std::wstring Name() const;

and do not forget to use type name you have defined:

                const SubMenuItem& SubMenuItems() const;
                void AddSubMenu(std::wstring name, int id);
                bool SubMenuPresent() const;
                typedef std::vector<MenuItem*> SubMenuItem;














in case of using auto_ptr to objects:

                typedef std::vector<std::auto_ptr<MenuItem> >
SubMenuItem;

you had better do not declare a destructor (compiler will generate a
proper one automaticall) or just define a trivial virtual destructor
that does not do anything.

But if you are using raw pointers :

                typedef std::vector<MenuItem*> SubMenuItem;

then simply delete the allocated pointer and leave the rest to the
compiler:

       MenuItem::~MenuItem()
        {
        // Iterate through all submenuitems
                for(SubMenuItem::iterator it =
m_subMenuItems.begin();
                    it != m_subMenuItems.end();
                    ++it)
                {
                        delete *it;
                }
        }






remember to use what you have defined:

          const SubMenuItem & MenuItem::SubMenuItems() const




make up your mind use either raw pointers:

          void MenuItem::AddSubMenu(std::wstring name, int id)
          {
                  m_subMenuItems.push_back(new MenuItem(name, id));
          }

or auto_ptr:

                typedef std::vector<std::auto_ptr<MenuItem> >
SubMenuItem;                 typedef std::vector<MenuItem*>
SubMenuItem;
oops!
it had to be like this:
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top