Jump to content

  • Log In with Google      Sign In   
  • Create Account

C++ vector of class objects referencing external class


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
17 replies to this topic

#1 Ubermeowmix   Members   -  Reputation: 312

Like
0Likes
Like

Posted 11 June 2013 - 03:53 AM

Hi,

 

Having trouble with the following code, it's giving me loads of errors but the main one is below giving the following

'std::vector<_Ty>::reserve' : cannot convert parameter 1 from 'unsigned int (__cdecl *)(void)' to 'unsigned int'

 

#include "Ctype.h"

class CBase
{
public:
    CBase(unsigned int spaces(1), char* cpName)  
        : m_strName(cpName) { m_vTypes.reserve(spaces); } // ERROR HERE

    ~CBase() {}

    std::string Name() { return m_strName; }

    void Add(const CType& rType) { m_vTypes.push_back(rType); } //awesome rType!

    std::vector<CType> mfRtnTypes()
    {
        return m_vTypes;
    }

private:
    std::vector<CType> m_vTypes;
    std::string m_strName;     
};

#endif

 

 

#ifndef CType_h
#define CType_h

class CType
{
public:
    CType(CBase* qpBase, int iInt)              
        : m_qpBase(qpBase), m_iInt(iInt) {} 
    ~CType() {}

    CBase* GetBase() { return m_qpBase; } 
    int GetInt() { return m_iInt; }

private:
    CBase* m_qpBase;
    int m_iInt;
};

#endif

 

#ifndef CUnit_h
#define CUnit_h

class CUnit : public CType
{
public:
    CUnit(CBase* qpBase) 
        : CType(qpBase, 2178) {}
    ~CUnit() {}

private:
};

#endif

 

In main function calling:

 

int iMaxTypes = 3;
    CBase newGroup(iMaxTypes, "Ubermeowmix");

    for(int i(0); i<iMaxTypes; ++i)
    {
        newGroup.Add( CUnit(&newGroup) );
    }

    for(int i(0); i<iMaxTypes; ++i)
    {
        cout << "Name of: " << newGroup.mfRtnTypes()[i].GetBase() << "\n";
        cout << "int of: " << newGroup.mfRtnTypes()[i].GetInt() << "\n";
    }

 

Can anyone help as I have no idea why it's throwing this!


Edited by Ubermeowmix, 11 June 2013 - 03:56 AM.

If you get near a point, make it!

Sponsor:

#2 kunos   Crossbones+   -  Reputation: 2207

Like
0Likes
Like

Posted 11 June 2013 - 03:59 AM

you need to forward declare the types you are using.

Google for "forward declarations".


Stefano Casillo
Lead Programmer
TWITTER: @KunosStefano
AssettoCorsa - netKar PRO - Kunos Simulazioni

#3 rnlf   Members   -  Reputation: 1120

Like
2Likes
Like

Posted 11 June 2013 - 04:09 AM

CBase(unsigned int spaces(1), char* cpName)

What's this (1) supposed to mean?


my blog (German)


#4 RobTheBloke   Crossbones+   -  Reputation: 2342

Like
0Likes
Like

Posted 11 June 2013 - 09:56 AM


    CBase(unsigned int spaces, char* cpName)  
        : m_strName(cpName) { m_vTypes.reserve(spaces); }



#5 rip-off   Moderators   -  Reputation: 8211

Like
5Likes
Like

Posted 11 June 2013 - 02:18 PM

Having trouble with the following code, it's giving me loads of errors but the main one is below giving the following

'std::vector<_Ty>::reserve' : cannot convert parameter 1 from 'unsigned int (__cdecl *)(void)' to 'unsigned int'

The compiler has interpreted "unsigned int spaces(1)" as a pointer to a function returning an unsigned integer and apparently taking no arguments. However, it appears to me that you are mistaken, from looking at your code there should be earlier error messages. Early errors can confuse the compiler and result in spurious and/or (extra) cryptic later errors. It is always a good idea to resolve the earliest error messages first, before trying to decipher later ones.



#6 Ubermeowmix   Members   -  Reputation: 312

Like
0Likes
Like

Posted 12 June 2013 - 04:39 AM

I think i'm getting mixed up with the relationship between class pointers and inheritance

 

I think i'm going to go back to my sudo code and start again.

 

Thanks guys.


If you get near a point, make it!

#7 Bregma   Crossbones+   -  Reputation: 5133

Like
0Likes
Like

Posted 12 June 2013 - 05:33 AM

CBase(unsigned int spaces(1), char* cpName)

It's pretty unusual to declare a function as a parameter like that.  Usually you'd do something like "unsigned int (*spaces)(int)".  Perhaps what you really meant was unsigned int spaces = 1, which assigns a default value to the argument, but since it's the first parameter that wouldn't be valid (default arguments must always be the rightmost parameters in the list).  You can not use the function-style initialization in a parameter list declaration because the rules of the language require it be parsed as a declaraion, same as any other declaration.  If you were using a compiler that implemented the current C++ standard, you could use a brace initializer list.

 

But the root of your problem is that you've declared the first parameter of CBase as a function pointer type, then passed it to the constructor of a std::vector type which tries to match it to available constructors, and the only available conversion is from function pointer type to integer type (for the initialize-with-default-values constructor), and that particular conversion is disallowed by the language without an explicit C-style cast.  It's actually exactly what the error message says.


Stephen M. Webb
Professional Free Software Developer

#8 Ubermeowmix   Members   -  Reputation: 312

Like
0Likes
Like

Posted 13 June 2013 - 04:33 AM

I think what I'm having trouble getting my head around is this:

 

If I create 3 classes:

 

CBase.h

CType.h //with inheritance to base

CUnit.h //with inheritance to type

 

and then declare a CUnit newUnit(myHealth);

 

does that create one object with three classes tagged to it? And can I store that one object in an array?

 

I essentially want a group of objects,

in each object is a group of units of a specific type.

But I want the code to be modular so I can tag on different unit types without rewriting the code over and over, because you can overload the functions using virtual for movement (etc) for each different type of unit.

The trouble I am having is accessing the member variables of the inherited classes from the base class.

Am I going about this the wrong way?


Edited by Ubermeowmix, 13 June 2013 - 04:37 AM.

If you get near a point, make it!

#9 Brother Bob   Moderators   -  Reputation: 8193

Like
2Likes
Like

Posted 13 June 2013 - 04:49 AM


I think what I'm having trouble getting my head around is this:



If I create 3 classes:



CBase.h

CType.h //with inheritance to base

CUnit.h //with inheritance to type



and then declare a CUnit newUnit(myHealth);



does that create one object with three classes tagged to it?

The type CUnit is a type that contains everything its derived classes contains. It has a CBase part, a CType part and whatever CUnit itself includes.


[...] And can I store that one object in an array?

I essentially want a group of objects,

in each object is a group of units of a specific type.

But I want the code to be modular so I can tag on different unit types without rewriting the code over and over, because you can overload the functions using virtual for movement (etc) for each different type of unit.

Am I going about this the wrong way?

You got the basic idea of inheritance and virtual functions along the right direction; yes, you can store different objects derived from CUnit and use virtual functions to automatically call the correct function for more derived classes.

 

However, this can only be achieved through pointers or references. Since you cannot store references in dynamic containers you need to work with pointers.

std::vector<CUnit *> units;
 
units.push_back(new CUnitA);
units.push_back(new CUnitB);
units.push_back(new CUnitC);

The three objects of the derived types  has to be dynamically allocated. You are strongly advised to use smart pointers instead of raw pointers though, but which one to use depends on how the ownership of the object shall be handled.



#10 Ubermeowmix   Members   -  Reputation: 312

Like
0Likes
Like

Posted 13 June 2013 - 05:41 AM


However, this can only be achieved through pointers or references. Since you cannot store references in dynamic containers you need to work with pointers.

std::vector<CUnit *> units;
 
units.push_back(new CUnitA);
units.push_back(new CUnitB);
units.push_back(new CUnitC);

The three objects of the derived types  has to be dynamically allocated. You are strongly advised to use smart pointers instead of raw pointers though, but which one to use depends on how the ownership of the object shall be handled.

 

Awesome i'll research smart pointers then.

 

So I can have a vector of groups, and within that vectors of units, does that massively affect memory usage?

 

Plus I've been looking into save files and I wanted to clear up something there too as it links to the same issue.

 

When saving is it better to parse out all the variables in the classes and write them like XML (for example) and then populate in reverse when loading?

 

P.S. gotta go to work so it's going to be a late reply.


Edited by Ubermeowmix, 13 June 2013 - 05:42 AM.

If you get near a point, make it!

#11 Brother Bob   Moderators   -  Reputation: 8193

Like
1Likes
Like

Posted 13 June 2013 - 07:20 AM

 

However, this can only be achieved through pointers or references. Since you cannot store references in dynamic containers you need to work with pointers.

std::vector<CUnit *> units;
 
units.push_back(new CUnitA);
units.push_back(new CUnitB);
units.push_back(new CUnitC);
The three objects of the derived types  has to be dynamically allocated. You are strongly advised to use smart pointers instead of raw pointers though, but which one to use depends on how the ownership of the object shall be handled.

 

Awesome i'll research smart pointers then.
 
So I can have a vector of groups, and within that vectors of units, does that massively affect memory usage?

 

 
Not saying anything about the design, but you certain can do that. Memory usage can mean different things though. Constant virtual dispatching if you're, say, iterating over the containers to call a virtual function on all units, may very well become a problem before the amount of memory used does. If you intend to use the type system to distinguish between similar units, then consider a data-driven approach instead. Do you really need the units to have different types instead of just having a single unit type with different data describing the type?
 

Plus I've been looking into save files and I wanted to clear up something there too as it links to the same issue.
 
When saving is it better to parse out all the variables in the classes and write them like XML (for example) and then populate in reverse when loading?
 
P.S. gotta go to work so it's going to be a late reply.

Serializing the data becomes a bigger problem if you, instead of using a data-driven approach with a single type, also have to determine the correct type within the language itself. Not only do you have to read the data from the external source, you also have to determine whether to call new on CUnitA, CUnitB or CUnitC on your data. Again, do you really need the different types?



#12 Ubermeowmix   Members   -  Reputation: 312

Like
0Likes
Like

Posted 15 June 2013 - 02:39 PM

Can anyone explain to me why the destructor is being called on the unit obects before I have called the delete unit function, I thought the pointer to new meant that they stayed in scope until the class obect group has been deleted from the vArmy vector?

 

Two questions:

 

1. how do I properly delete an object when it is created dynamically in a class (or is it culled when the class is deleted?).

 

2. Is a vector a pointer already, and if so when things are passed into it do they need to be zeroed out when being deleted?

 

class CGroup
{
public:
    CGroup()
    {
        CUnit* pNewUnit = new CUnit(0, 5);
        m_vTroups.push_back( *pNewUnit );    
    }
    ~CGroup() {}
    
    void mfAddUnit(int type, int health)
    {
        std::cout << "Unit created!\n";
        m_vTroups.push_back( CUnit( type, health) );
    }
 
    void mfDelUnit(size_t index)
    {
        m_vTroups.erase(m_vTroups.begin() + index);
    }

    std::vector<CUnit> mfRtnVector() const
    {
        return m_vTroups;
    }

    size_t size() const
    {
        return m_vTroups.size();
    }
private:
    std::vector<CUnit> m_vTroups;
    int m_iNumber;
};

 

class CUnit
{
public:
    CUnit()
    {
        m_iType = 0;
        m_iHealth = 5;        
    }

    CUnit(int iT, int iH)
    {
        std::cout << "CUnit type " << iT << ", health " << iH << " \n";
        m_iType = iT;
        m_iHealth = iH;
    }
    ~CUnit() {}

    void mfirSetInt(int iT, int iH) { m_iType = iT; m_iHealth = iH; }
    void mfirGetInt(int& iT, int& iH) { iT = m_iType; iH = m_iHealth; }

private:
    int m_iType;
    int m_iHealth;
};

 

int main()

{

    std::vector<CGroup> vArmy;

    CGroup* pNewGroup = new CGroup;
    vArmy.push_back( *pNewGroup );

    //etc

}


If you get near a point, make it!

#13 Brother Bob   Moderators   -  Reputation: 8193

Like
1Likes
Like

Posted 15 June 2013 - 03:01 PM

Don't allocate the items with new. For example, in main, you allocate a new CGroup object, and put a copy of it into the vArmy vector. The allocated object is then lost in void and you have a memory leak. The destructor being called is the destructor for the object in the vArmy vector.

 

int main()
{
    std::vector<CGroup> vArmy;

    vArmy.push_back( CGroup() );
 }


#14 Brother Bob   Moderators   -  Reputation: 8193

Like
1Likes
Like

Posted 15 June 2013 - 03:07 PM

Sorry, I missed that you actually had two explicit questions.
 

Can anyone explain to me why the destructor is being called on the unit obects before I have called the delete unit function, I thought the pointer to new meant that they stayed in scope until the class obect group has been deleted from the vArmy vector?
 
Two questions:
 
1. how do I properly delete an object when it is created dynamically in a class (or is it culled when the class is deleted?).

delete what you new, but when working with values, like std::vector<CGroup> instead of std::vector<CGroup *>, you don't have to new anything so there's nothing to delete either.
 

2. Is a vector a pointer already, and if so when things are passed into it do they need to be zeroed out when being deleted?

A vector stores values of the type you specify. If you ask it to store instances of CGroup, that is std::vector<CGroup>, then no pointers are stored, only values and copies of CGroup instances.



#15 SiCrane   Moderators   -  Reputation: 9594

Like
0Likes
Like

Posted 15 June 2013 - 03:14 PM

Note that if you have a C++11 compiler, you can use emplace_back() instead of push_back(), which constructs the object in place with the arguments you supply without needing to make a copy. So instead of
m_vTroups.push_back( CUnit( type, health) );
You can have
m_vTroups.emplace_back(type, health);


#16 Ubermeowmix   Members   -  Reputation: 312

Like
0Likes
Like

Posted 15 June 2013 - 04:48 PM


2. Is a vector a pointer already, and if so when things are passed into it do they need to be zeroed out when being deleted?

A vector stores values of the type you specify. If you ask it to store instances of CGroup, that is std::vector<CGroup>, then no pointers are stored, only values and copies of CGroup instances.

 

This is the part i'm having trouble with, when in the class object CGroup and loading the CUnit on the fly into the vector within CGroup, the destructor of CUnit is called if I use a pointer or not. Why does it do this, is the vector being deleted or the CUnit being deleted?

 

Or is the complier calling the destructor everytime I read the objects of the vector?


If you get near a point, make it!

#17 SiCrane   Moderators   -  Reputation: 9594

Like
1Likes
Like

Posted 15 June 2013 - 04:59 PM

Every time you use push_back() to put something in a vector, the vector makes a copy of the object you pass it. If you pass push_back() a temporary object, the vector will make a copy of the temporary and then the compiler will destroy the temporary. It's also possible that they way you're reading from the vector is also generating extra temporary objects.

 

How are you tracking your CUnit destruction? It's entirely possible that you aren't seeing matching construction and destruction counts because you aren't tracking copy constructor calls.



#18 Ubermeowmix   Members   -  Reputation: 312

Like
0Likes
Like

Posted 16 June 2013 - 02:41 AM

How are you tracking your CUnit destruction? It's entirely possible that you aren't seeing matching construction and destruction counts because you aren't tracking copy constructor calls.

I just put a cout << "destructor called in CUnit\n"; in the destructor, so is this just the compiler making a copy of the object in the vector to read it temporarily? I've taken the pointer out of:

CUnit* pNewUnit = new CUnit(0, 5);
m_vTroups.push_back( *pNewUnit );

 

As you said I don't really need it with the vector. I am using a custom copy constructor:

CUnit(int iT, int iH)
    {
        std::cout << "CUnit COPY constructor called\n";
        m_iType = iT;
        m_iHealth = iH;        
    }

But as i've been reading through it looks apparent that I don't need to use referencing unless there are member pointers in the class!


If you get near a point, make it!




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS