Below I have written a sample program that I have written to learn about passing a list of objects to another class. I talk about the problems I am having below.
#include <iostream>
#include <vector>
using namespace std;
class Integer_Class
{
int var;
public:
Integer_Class(const int& varin) : var(varin) {}
int get_var() { return var; }
};
class Contains_List
{
typedef Integer_Class* Integer_Class_Star;
Integer_Class_Star list;
public:
Contains_List(const Integer_Class_Star& listin) : list(listin) {}
Integer_Class* get_list() { return list; }
};
int main (int argc, char * const argv[])
{
// Create a vector to contain a list of integers.
vector<Integer_Class> list;
for(int i = 0; i < 10; i++)
{
Integer_Class temp_int(i);
list.push_back(temp_int);
}
This is where the errors start occuring. Could someone please look at the second class definition and the code below and shed some light on what I'm doing wrong. Thank you so much, as always!
// Import this list as an object into another object.
Contains_List final(list);
// Output the elements of the list by accessing it through the secondary object.
for(int i = 0; i < 10; i++)
{
cout << final.get_list()[i].get_var();
}
return 0;
}
You don't mention what sort of errors you are getting, but one very obvious problem with your code is that the constructor for Contains_List expects a pointer to Integer_Class while the parameter you are sending it (list) is of type vector<Integer_Class>.
A vector is not the same as an array, so you cannot pass it as pointer to the type it contains. Either change your constructor to accept a vector or pointer/reference to vector, or change the code that is causing you problems so that it sends it a pointer to an array.
The 'Contains_List' constructor takes in an 'Integer_Class*'
You declare 'list' to be of type 'vector', yet you pass it to the the 'Contians_List' constructor. You should change the 'Contains_List' class so that it holds a vector instead of an Integer_List array. The two are not interchangeable.
You could also change the vector to be an array of Integer_List's instead, if you so wished.
Related
Sorry for the confusing title, basically I have created two classes, one is an object, and the other being a box that contains an array of such objects. so what I want to do is create a function/constructor inside the object class that takes in an array of ints and stores them inside the box. I want to be able to call this function through the box class constructor to initialize these objects. So ive tried something like below but it isnt working at all, since only the first value of the array gets passed through. What am I doing wrong?
#include <iostream>
#include <string>
class object{
string objectName;
int values[];
public:
void createObject(int[]);
}
class Box{
object objects[100];
public:
Box();
}
Box::Box (void){
int array1[2];
int array2[15];
object[1].createObject(array1);
object[2].createObject(array2);
}
Object::Object(int Values[]){
values = Values;
}
You should really use std::vector. The problem with arrays is that they decay to pointers when passed as arguments to functions. As a consequence, If you want to store a private copy of the elements you are forced to use heap-allocated objects and consequently do memory management by hand (with all the pain it causes).
It is much better to rely on data members that permit applying the rule of zero.
Here's a tentative solution:
#include <iostream>
#include <string>
#include <vector>
class object {
public:
object(std::vector<int> const& v, std::string const& object_name): v_(v.begin(), v.end()), object_name_(object_name) {}
private:
std::vector<int> v_;
std::string object_name_;
};
class box {
public:
box(std::vector<object> const& objects): objects_(objects) {};
private:
std::vector<object> objects_;
};
I recommend you instead use a std::vector. Arrays don't really work well being passed to functions. When you define Object::Object(int Values[]) you are simply passing the first element of this array by value. If you were to use vectors, the function would look like this:
Object::Object(std::vector<int> &Values):
values(Values)
{
}
The problem with the code is in your thinking on what the array is. In C++, all an array is, is a memory pointer. The language allows you to pass an index into the array pointer to access whatever chunk of data lives at that index.
Whenever you pass arrays between functions or classes, pass the array name only. It will be interpreted as a pointer, and won't copy any data. When you do this, you must also pass the length of the array.
Granted, most people stick with vector<> because it's easier, takes care of memory leaks (mostly) and is VERY efficient. But I like doing it myself. It's good for you. I would try:
#include <iostream>
#include <string>
class Object
{
string _objectName;
int *_values;
int _myLength;
Object();
~Object();
void createObject(int *pValues, int arrLength);
}
class Box
{
_Object objects[100];
Box();
}
Box::Box(void) {
int array1[2];
int array2[15];
object[1].createObject(array1, 2);
object[2].createObject(array2, 15);
}
Object::Object() {
_values = null_ptr;
_myLength = 0;
}
Object::~Object() {
delete[] _values;
}
void Object::createObject(int *pvalues, int arrLength) {
_myLength = arrLength;
_values = new int[_myLength];
for(int ndx=0; ndx<arrLength; ndx++) {
_values[ndx] = pvalues[ndx];
}
}
-CAUTION-
I just adapted your code you provided, and added some conventions. There are a couple places in the code where I'm not sure what the purpose is, but there you go. This should give you a good head start.
Hello fellas when I'm trying to create multiply objects from a object and want to call for the constructor I'm getting som strange error.
the error is: a value of type const cha*r cannot be used to initialize an entity of type Obstacle[3]
Creating objects here referes to the Player object because it works, even if I try to for-loop to set my ("img....") I'm getting the same error
static const int CAP = 3;
//Works! Player player = ("img/playerSheet.png");
Obstacle obstacles[CAP] =("img/obstacle.png");
The Obstacle constructor looks like this
Obstacle::Obstacle(string spriteSearch) : Object(spriteSearch)
{
setPosition(750, 500);
}
//Filip
You are using the incorrect method of declaring an array. You create an array that holds three objects. You need to initialize each object with the default constructor. Here is one way to do it.
If you havent seen structs before, dont worry. All you need to know it works like a small class.
#include <iostream>
#include <string>
using namespace std;
struct Object
{
string name;
Object(string _name)
{
name = _name;
}
};
int main()
{
Object obs[3] = {"one", "two", "three"};
cout<<obs[0].name<<obs[1].name<<obs[2].name<<endl;
system("pause");
return 0;
}
Edit; If you have a large capacity, say 1000. I would suggest adding a seperate function. Where you dont initialize in the default constructor, but actually creates an Initialize function. That you call after. As an example;
Obstacle obstacles[CAP];
for(int i=0; i<CAP; i++)
{
obstacles[i].Initialize("img/playerSheet.png");
}
Comment: "Alright, i just edited the constructor above i wrote wrong before... so you mean to forloop and the how do i call the constructor, like obstaclei;? :O"
I might be in the wrong here. But I think in order to call the actual constructor, the only way is to do it like this:
Change:
Obstacle obstacles[CAP] =("img/obstacle.png");
to something like;
const int CAP = 5;
Object** obstacles = new Object*[CAP];
for(int i = 0; i<CAP; i++)
{
obstacles[i] = new Object(filename);
}
//Do other stuff. And when done, release memory.
for(int i=0; i<CAP; i++)
{
delete obstacles[i];
}
delete []obstacles;
It's fairly complicated solution if you are not used to using pointers.
I encountered an issue that I have been trying to solve for some time, and simply couldn't do it. Here is the scenario:
1) I have an Template array class that look something like this
//code taken from http://www.learncpp.com, much appreciation for Alex
#ifndef ARRAY_H
#define ARRAY_H
#include <assert.h> // for assert()
template <typename T>
class Array {
private:
int m_nLength;
T *m_ptData;
public:
Array() {
m_nLength = 0;
m_ptData = 0;
}
Array(int nLength) {
m_ptData= new T[nLength];
m_nLength = nLength;
}
~Array() {
delete[] m_ptData;
}
void Erase() {
delete[] m_ptData;
m_ptData= 0;
m_nLength = 0;
}
T& operator[](int nIndex) {
assert(nIndex >= 0 && nIndex < m_nLength);
return m_ptData[nIndex];
}
int GetLength() { return m_nLength; }
friend ostream& operator<<(ostream& out, const Array<T>& n) {
for(int i=0; i<n.m_nLength; i++) {
if(i) it << "\n";
it << n[i];
}
return it;
}
};
#endif
2) And this is the class I tried making array of and how I did it (it has dynamic memory allocation)
class Tune {
char* artist;
char* song;
public:
explicit Tune(const char* a, const char* s) {
artist = new char [strlen(a)+1]; strcpy(artist, a);
song = new char [strlen(s)+1]; strcpy(song, s);
}
...
#include "Array.h"
void main() {
Array<Tune> tunes(5); //Array of 5 elements
}
error C2512: 'Tune' : no appropriate default constructor available
1> c:\x\x\x\visual studio 2010\projects\x\x\array.h(26) : while
compiling class template member function 'Array<T>::Array(int)'
1> with
1> [
1> T=Tune
1> ]
1> c:\x\x\x\visual studio 2010\projects\x\x\main.cpp(10) : see reference to
class template instantiation 'Array<T>' being compiled
1> with
1> [
1> T=Tune
1> ]
3) Then I remembered that I could solve that issue with something like this (without using my array template class):
void main() {
Tune **tunes = new Tune*[5];
...
}
I would like to know is this the solution and how do I create Array of pointers using my template array class, and second (lest say I have overriden operator<<), how to I print one or all of the elements of the array.
The full program is huge, this is the piece of it. Most of the code is under comments, so the issue is isolated.
I am pretty stuck and this project means a lot to me, but I am an inexperienced programmer so I find it hard to handle issue like this. Thanks for help in advance.
Cheers!
First of all please show the full error message. Secondly it is not clear what is MyType and whether it has the default constructor.
If MyType is for example some arithmetic type then the code below will be compiled without errors.
#include "Array.h"
int main() {
Array<MyType> data(5); //Array of 5 elements
}
At least class Array has the default constructor though it is not used. As for the type MyType then it can be said nothing because you did not show neither the full error message nor the definition of MyType.
I suggest to check whether MyType has the default constructor.
If you want to create an array of pointers then you should write
Array<MyType *> data(5);
As for this code
void main() {
MyType **data = new MyType*[5];
...
}
then it has nothing common with the problem. Take into account that main shall be defined as having return type int.
EDIT: If do not take into account errors in the definition of class Tune, then it has no default constructor. So you should decide whether you want to create an array of obects of type Tune or an array of pointers to objects of type Tune. I already showed how fo define the array of pointers. Or define the default constructor for class Tune.
How do I create an array of pointers using my template Array class?
If your class needs an alternate way of constructing its elements, you should create another constructor that initializes it the way you wish, similar to std::vector's constructor:
Array( int count, const T& value );
The easiest way to implement this would be to declare m_ptData as a double pointer and initialize it like so:
Array( int count, const T& value ) : m_ptData(new T*[count])
{
for (int i = 0; i < count; ++i)
{
m_ptData[i] = new T(value);
}
}
The best (and most difficult) way would be to use placement-new to initialize it, this is how std::vector does it. You can use it like this:
int main()
{
Array<MyType> data(5, MyType("abc")); // Array of 5 elements,
// all initialized to MyType("abc")
}
How do I print one or all of the elements of the array?
The inserter operator<<() should be used to print the entire array, so making it do something like printing only some of the elements would be a bit confusing to maintainers of your code. As alternatives, you can create a stream manipulator if you wish to customize output, or you can use a member function that takes a count of the numbers you would like to print. Also, your class can have begin() and end() functions which return pointers to the beginning and end of the array, so the user of the class can implement the printing at their discretion. In either cases, looping should be used to print the elements.
I have a relatively simple question but I cant seem to find an answer specific for my case and I just may not be approaching this problem the right way. I have a class that looks like this:
struct tileProperties
{
int x;
int y;
};
class LoadMap
{
private:
ALLEGRO_BITMAP *mapToLoad[10][10];
tileProperties *individualMapTile[100];
public:
//Get the struct of tile properties
tileProperties *getMapTiles();
};
I have an implementation that looks like this for the getter function:
tileProperties *LoadMap::getMapTiles()
{
return individualMapTile[0];
}
I have code in the LoadMap class that will assign 100 tile properties for each struct in the array. I want to be able to access this array of structs in my main.cpp file but I just cant seem to find the right syntax or approach. My main.cpp looks like this.
struct TestStruct
{
int x;
int y;
};
int main()
{
LoadMap _loadMap;
TestStruct *_testStruct[100];
//This assignment will not work, is there
//a better way?
_testStruct = _loadMap.getMapTiles();
return 0;
}
I realize that there are many approaches to this, but I'm trying to keep this implementation as private as possible. If someone could please point me in the right direction I would greatly appreciate it. Thank you!
TestStruct *_testStruct;
_testStruct = _loadMap.getMapTiles();
This will get you a pointer to the first element in the array returned. You can then iterate through the other 99.
I would highly recommend using vectors, or another container, and writing getters that don't return pointers to bare arrays like that.
First of all, here, why do we need TestStruct, you can use "tileProperties" structure itself...
And imp thing,
tileProperties *individualMapTile[100]; is array of pointers to the structure.
Hence, individualMapTile will have pointers in it.
You have returned the first pointer, hence you can access the first structure only. What about the others????
tileProperties** LoadMap::getMapTiles()
{
return individualMapTile;
}
int main()
{
LoadMap _loadMap;
tileProperties **_tileProperties;
_tileProperties = _loadMap.getMapTiles();
for (int i=0; i<100;i++)
{
printf("\n%d", (**_tileProperties).x);
_tileProperties;
}
return 0;
}
Use vectors instead of arrays where possible. Also consider an array/vector of TestStruct directly rather than pointers to them. I can't tell if that would be appropriate for you from your code sample.
class LoadMap
{
public:
typedef vector<tileProperties *> MapTileContainer;
LoadMap()
: individualMapTile(100) // size 100
{
// populate vector..
}
//Get the struct of tile properties
const MapTileContainer& getMapTiles() const
{
return individualMapTile;
}
MapTileContainer& getMapTiles()
{
return individualMapTile;
}
private:
MapTileContainer individualMapTile;
};
int main()
{
LoadMap _loadMap;
LoadMap::MapTileContainer& _testStruct = _loadMap.getMapTiles();
}
I am trying to create an array of class objects taking an integer argument. I cannot see what is wrong with this simple little code. Could someone help?
#include <fstream>
#include <iostream>
using namespace std;
typedef class Object
{
int var;
public:
Object(const int& varin) : var(varin) {}
} Object;
int main (int argc, char * const argv[])
{
for(int i = 0; i < 10; i++)
{
Object o(i)[100];
}
return 0;
}
In C++ you don't need typedefs for classes and structs. So:
class Object
{
int var;
public:
Object(const int& varin) : var(varin) {}
};
Also, descriptive names are always preferrable, Object is much abused.
int main (int argc, char * const argv[])
{
int var = 1;
Object obj_array[10]; // would work if Object has a trivial ctor
return 0;
}
Otherwise, in your case:
int main (int argc, char * const argv[])
{
int var = 1;
Object init(var);
Object obj_array[10] = { var, ..., var }; // initialize manually
return 0;
}
Though, really you should look for vector
#include <vector>
int main (int argc, char * const argv[])
{
int var = 1;
vector<Object> obj_vector(10, var); // initialize 10 objects with var value
return 0;
}
dirkgently's rundown is fairly accurate representation of arrays of items in C++, but where he is initializing all the items in the array with the same value it looks like you are trying to initialize each with a distinct value.
To answer your question, creating an array of objects that take an int constructor parameter. You can't, objects are created when the array is allocated and in the absence of a trivial constructor your compiler will complain. You can however initialize an array of pointers to your object but you really get a lot more flexibility with a vector so my following examples will use std::vector.
You will need to initialize each of the object separately if you want each Object to have a distinct value, you can do this one of two ways; on the stack, or on the heap. Lets look at on-the-stack first.
Any constructor that take a single argument and is not marked as explicit can be used as an implicit constructor. This means that any place where an object of that type is expected you can instead use an instance of the single parameter type. In this example we create a vector of your Object class and add 100 Objects to it (push_back adds items to a vector), we pass an integer into push_back which implicitly creates an Object passing in the integer.
#include <vector>
int main() {
std::vector<Object> v;
for(int i = 0; i < 100; i++) {
v.push_back(i);
}
}
Or to be explicit about it:
#include <vector>
int main() {
std::vector<Object> v;
for(int i = 0; i < 100; i++) {
v.push_back(Object(i));
}
}
In these examples, all of the Object objects are allocated on the stack in the scope of the for loop, so a copy happens when the object is pushed into the vector. Copying a large number of objects can cause some performance issues especially if your object is expensive to copy.
One way to get around this performance issue is to allocate the objects on the heap and store pointers to the objects in your vector:
#include <vector>
int main() {
std::vector<Object*> v;
for(int i = 0; i < 100; i++) {
v.push_back(new Object(i));
}
for(int i = 0; i < 100; i++) {
delete v[i];
}
}
Since our objects were created on the heap we need to make sure that we delete them to call their deconstructor and, free their memory, this code does that in the second loop.
Manually calling delete has it's own caveats, if you pass these pointers to other code you can quickly loose track of who owns the pointers and who should delete them. An easier way to solve this problem is to use a smart pointer to track the lifetime of the pointer, see either boost::shared_ptr or tr1::shared_ptr which are reference-counted pointers :
#include <vector>
int main() {
std::vector<shared_ptr<Object> > v;
for(int i = 0; i < 100; i++) {
Object* o = new Object(i);
v.push_back(shared_ptr<Object>(o));
}
}
You'll notice that the shared_ptr constructor is explicit, this is done intentionally to make sure that the developer is intentionally stuffing their pointer into the shared pointer. When all references to an object are released the object will automatically be deleted by the shared_ptr, freeing us of the need to worry about it's lifetime.
If you want to stick to arrays, then you must either initialize manually or use the default constructor. However, you can get some control by creating a constructor with a default argument. This will be treated as a default constructor by the compiler. For example, the following code prints out the numbers 0, ..., 9 in order. (However, I'm not sure that the standard dictates that the objects in the array must be constructed in order. It might be implementation dependent, in which case the numbers may appear in arbitrary order.)
#include <iostream>
using namespace std;
struct A {
int _val;
A(int val = initializer()) : _val(val) {}
static int initializer() { static int v = 0; return v++; }
};
int main()
{
A a[10];
for(int i = 0; i < 10; i++)
cout << a[i]._val << endl;
}