instantiating a class object (template) from a base class - c++

Warning newby
Base class trying to instantiate template class
Rather than put all the code in , I'll try excerpts for brevity
Base class constructor has error: Trying to create an object of template class Queue.
There is a typedef setting data_type = Card (a
common class).
DeckOfCards::DeckOfCards()
{
Queue<data_type>* deck;
deck = new Queue<data_type>;
fill_deck(deck&); **"error: expected primary-expression before ‘)’ token"**
}
**fill_deck declaration:**
from the header : void fill_deck(const Queue<data_type>& data);
void DeckOfCards::fill_deck( const Queue<data_type>& deck)
{
for (int i=0; i < 4 ; i++)
{
for (int j=1; j< 14 ; j++)
{
if ( j == 11 ) {
cardID = "J" + suits[i];
cardValue = 10;
} else
if ( j == 12 ) {
cardID = "Q" + suits[i];
cardValue = 10;
} else
if ( j == 13 ) {
cardID = "K" + suits[i];
cardValue = 10;
} else {
cardID = suits[i] + IntToString(j);
cardValue = j;
}
cardFacing = false;
Card* cardPtr = new Card(cardID,cardValue, cardFacing);
deck.enqueue(cardPtr&); **"error: expected primary-expression before ‘)’ token"**
delete cardPtr;
}
}
cout << "\nFinished add " ;
}
Method enqueue from Template Queue:
template <class data_type>
void Queue<data_type>::enqueue(const data_type& data){
qList->addToTail(data);
length++;
}
The plan was to create a Queue class object and populate that queue
with type Card another class. I couldn't Pass a reference parameter to
the function DeckOfCards::fill_deck() and I couldn't refer to the new
Queue object.
Any help appreciated

fill_deck accepts a reference const Queue<data_type>& so since you created a pointer
Queue<data_type>* deck;
deck = new Queue<data_type>;
you'd dereference it to call fill_deck
fill_deck(*deck);
similar problem later, which should be
deck.enqueue(*cardPtr);
As a general note, you have a lot of new allocations that likely could instead be stack allocated. You're likely leaking memory by doing so, though it is hard to say without seeing the context of the rest of the class design.

Related

Print a string from a pointer to its member class

So I'm trying to print a string, but I get no output. However the other values in the class prints just fine.
In main I have a for loop that prints the the values for the Skill class. In Skill I have a pointer to the Ability class.
class Skill {
private:
Ability* ability;
public:
Ability* GetAbility() {
return ability;
};
}
It gets assigned in the constructor like this:
Skill::Skill(Ability* ability){
this->ability = ability;
}
The Ability class contains just a Name and a score.
class Ability {
private:
string name;
float score;
public:
Ability(string name, float score) {
this->name = name;
this->score = score;
};
string Name() { return name; }
float GetScore() { return score; }
};
Now in main I create a few skills and assign an ability to it. as is a container class that initializes a few ablities in a vector and I can get an ability based on its name.
Skill s* = new Skill[2]
s[0] = Skill(&as.GetAbility("Strength"));
s[1] = Skill(&as.GetAbility("Charisma"));
And then we print
cout << s[i].GetAbility()->Name() << " " << s[i].GetAbility()->GetScore();
However the only output I get is the score. No name what so ever and I can't figure it out. I've tried a few things, but still noting is printing. I'm sure I'm missing something simple that will make me facepalm, but in my defense I haven't written C++ in over 10 years. Thanks in advance.
EDIT: as.GetAbility looks like this:
Ability AbilityScores::GetAbility(string abilityName) {
for (int i = 0; i < abilityScores.size(); i++) {
if (abilityScores[i].Name() == abilityName) {
return abilityScores[i];
}
}
return Ability();
}
abilityScores is a vector
Your AbilityScores::GetAbility() method is returning an Ability object by value, which means it returns a copy of the source Ability, and so your Skill objects will end up holding dangling pointers to temporary Ability objects that have been destroyed immediately after the Skill constructor exits. So your code has undefined behavior.
AbilityScores::GetAbility() needs to return the Ability object by reference instead:
Ability& AbilityScores::GetAbility(string abilityName) {
for (int i = 0; i < abilityScores.size(); i++) {
if (abilityScores[i].Name() == abilityName) {
return abilityScores[i];
}
}
throw ...; // there is nothing to return!
}
...
Skill s* = new Skill[2];
s[0] = Skill(&as.GetAbility("Strength"));
s[1] = Skill(&as.GetAbility("Charisma"));
...
If you want to return a default Ability when the abilityName is not found, consider using std::map instead of std::vector:
private:
std::map<std::string, Ability> abilityScores;
AbilityScores::AbilityScores() {
abilityScores["Strength"] = Ability("Strength", ...);
abilityScores["Charisma"] = Ability("Charisma", ...);
...
}
Ability& AbilityScores::GetAbility(string abilityName) {
// if you don't mind Name() returning "" for unknown abilities...
return abilityScores[abilityName];
// otherwise...
auto iter = abilityScores.find(abilityName);
if (iter == abilityScores.end()) {
iter = abilityScores.emplace(abilityName, 0.0f).first;
}
return iter->second;
}
...
Skill s* = new Skill[2];
s[0] = Skill(&as.GetAbility("Strength"));
s[1] = Skill(&as.GetAbility("Charisma"));
...
Otherwise, return the Ability object by pointer instead:
Ability* AbilityScores::GetAbility(string abilityName) {
for (int i = 0; i < abilityScores.size(); i++) {
if (abilityScores[i].Name() == abilityName) {
return &abilityScores[i];
}
}
return nullptr;
// or:
abilityScores.emplace_back(abilityName, 0.0f);
return &(abilityScores.back());
}
...
Skill s* = new Skill[2];
s[0] = Skill(as.GetAbility("Strength"));
s[1] = Skill(as.GetAbility("Charisma"));
...

C++ - Insertion in a Linked List without using a node's constructor. Is it possible?

I'm working on implementing a Templated Linked List in C++ that will be used to simulate a train moving through numerous stops where traincars are both added and removed. Traincar is its own class and each object is supposed to be given a unique ID starting with 1 and incremented when a car is added. However, when running my code, the id is being incremented more than it is supposed to.
After some experimentation and with help from previous answers, I have determined that it is the new node statements within my LinkedList class methods that are causing the id to be incremented more than wanted. However, I do not see a way to implement insertion methods without creating a new node. Is there any way around this?
Here is my TrainCar class:
class TrainCar {
public:
static int nextID;
int id;
char typeOfCar;
int numberOfStops;
node<char>* car;
TrainCar();
};
int TrainCar::nextID = 1;
TrainCar::TrainCar() {
cout << "id++" << endl;
id = nextID++;
int i = (rand() % 3);//gives a random number 0 - 2, used to determine what
//type of car to add
if(i == 0) {
typeOfCar = 'P';
}
else if(i == 1) {
typeOfCar = 'C';
}
else {
typeOfCar = 'M';
}
car = new node<char>(typeOfCar);
numberOfStops = (rand() % 5) + 1;//gives a random number 1 - 5;
}
Here is my main() function
int main() {
LinkedList<TrainCar> train;
int addCargoCar = 0;
for(int i = 0; i < 10; i++) {
TrainCar newCar;
if(newCar.typeOfCar == 'P') {
train.AddToFront(newCar);
addCargoCar++;
}
else if(newCar.typeOfCar == 'C') {
train.AddAtIndex(newCar, addCargoCar);
}
else {
train.AddToEnd(newCar);
}
}
cout <<"Welcome to the Train Station! Here is your train!" << endl;
char type;
int id, numberOfStops, i, j;
for(i = 0; i < train.size; i++) {
type = train.Retrieve(i).typeOfCar;
id = train.Retrieve(i).id;
numberOfStops = train.Retrieve(i).numberOfStops;
cout << "[" << id << ":" << type << ":" << numberOfStops << "] ";
}
}
The output should be something similar to
[5:P:1][6:P:4][8:P:2][3:P:2][10:C:3][2:C:3][4:C:1][1:M:1][7:M:3][9:M:2]
But my output is:
[17:P:2][9:P:2][5:C:2][19:C:1][15:C:2][1:M:5][3:M:4][7:M:1][11:M:3][13:M:1]
Edit: Here is the AddToFront() method: (all other add methods are similar in nature). The issue with the output is the new node<T>(d) statements
template <class T>
void LinkedList<T>::AddToFront(T d) {
node<T>* newNode = new node<T>(d);
if(head == NULL) {
head = newNode;
tail = newNode;
size++;
}
else {
newNode->next = head;
head = newNode;
size++;
}
}
Edit2: Here is my Retrieve function (now fixed, it no longer uses a new node statement):
template <class T>
T LinkedList<T>::Retrieve(int index) {
node<T>* cur = head;
for(int i = 0; i < index; i++) {
cur = cur->next;
}
return(cur->data);
}
You have the right idea to use a static member variable to keep track of identifiers. But you can't use only that.
The static member variable is a member of the class and not any specific object. Therefore all object share the same id.
Use a static member to keep track of the next possible id, and then use a non-static member variable to store the actual id for the object.
Something like
class TrainCar {
public:
static int next_id; // Used to get the id for the next object
int id; // The objects own id
...
};
TrainCar::TrainCar() {
id = next_id++; // Get next id and save it
...
}
You should probably also have a copy-constructor and copy-assignment operator, otherwise you could get two objects with the same id.
Regarding
Why are the id values so high and why are they being incremented by more than one each time?
That's because you probably create more objects than you expect. With the code you show, as well as with the change suggested above, you will create a new id for every object that is default-constructed. And depending on what your LinkedList template class is doing (why don't you use std::vector) there might be new objects created.
An educated guess is that the Retreive function of your list class default constructs the object it contain. That's why you get three objects constructed when printing, as you call Retrieve three times. Probably a similar story about your Add functions.

What is the right way of passing an object to a template constructor or method

I have a Shop template class and a Cookie class and trying to create a dynamic array of Cookie kind (or something else's kind since it is a template) and add more if required as follows in my main function such as:
template <typename shopType>
class Shop {
private:
int noi; // number of items
double totalcost;
shopType * sTptr; // for dynamic array
public:
Shop(shopType &);
void add(shopType &);
.....
and
int main() {
.....
Cookie cookie1("Chocolate Chip Cookies", 10, 180);
Cookie cookie2("Cake Mix Cookies", 16, 210);
Shop<Cookie> cookieShop(cookie1); // getting error here
cookieShop.add(cookie2); // and here
.....
with constructor and methods I wrote like:
template<typename shopType>
Shop<shopType>::Shop(shopType & sT)
{
sTptr = new shopType;
sTptr = sT; // not allowed, how can I fix ?
noi = 1;
totalcost = sT.getCost();
}
template<typename shopType>
void Shop<shopType>::add(shopType & toAdd)
{
if (noi == 0) {
sTptr = new shopType;
sTptr = toAdd; // not allowed, how can I fix ?
totalcost = toAdd.getCost();
noi++;
}
else {
shopType * ptr = new shopType[noi + 1];
for (int a = 0; a < noi; a++) {
ptr[a] = sTptr[a];
}
delete[] sTptr;
sTptr = ptr;
sTptr[noi++] = toAdd;
totalcost += toAdd.getCost();
}
}
and I am naturally getting C2440 '=': cannot convert from 'Cookie' to 'Cookie *' error...
I understand what I am doing wrong but I can't figure it out how to do it in the right way...
Should creating a new Cookie pointer and copying the one in parameter to it would work, or something else? Any suggestions ? Thanks in advance.
The error message from the compiler is pretty clear. You are trying to assign a shopType to a shopType* in the line:
sTptr = toAdd;
Unless you have very strong reasons for managing memory for the array yourself, use a std::vector to store the objects in a Shop.
template <typename shopType>
class Shop {
private:
// There is no need for this.
// int noi; // number of items
double totalcost;
std::vector<shopType> shopItems;
// ...
};
Then, Shop::add can be implemented simply as (I changed the argument type to a const reference):
template<typename shopType>
void Shop<shopType>::add(shopType const& toAdd)
{
shopItems.push_back(toAdd);
}

Destructor called after returning from function

I've got some project for my University and I need to perform converting some data from file to matrix representation.
The main problem is that after returning form "returnNeighbours(int node)" destructor is called on neighbours object(as I concluded from running gdb).
I know that destructor is always called when local variable, in function, is initialized, but neihbours is a class member. I won't post everything, because it's not necessary I think. I've got some structures listed below.
representation.cpp
NodeContainer::NodeContainer(){ size = 0; array = nullptr; }
NodeContainer::~NodeContainer(){ size = 0; delete[] array; }
void NodeContainer::allocateMemoryAndSetSize(int n){ size = n; array = new int[size]; }
void MatrixRep::convertDataToMatrixRep(int** array)
{
for(int i = 0 ; i != size; i++)
for(int j = 0; j != size; j++)
matrix[i][j] = array[i][j];
}
NodeContainer MatrixRep::returnNeighbours(int node)
{
deleteNeighboursIfAny();
if(!checkIfNotBeyondMatrix(node))
return neighbours;
neighbours.allocateMemoryAndSetSize(countNeighbours(node));
for(int i = 0, j = 0; i < size; i++)
if(matrix[node-1][i] != 0)
{
neighbours.array[j] = matrix[node-1][i];
j++;
}
return neighbours;
}
void MatrixRep::deleteNeighboursIfAny(){ if(neighbours.array) neighbours.~NodeContainer(); }
bool MatrixRep::checkIfNotBeyondMatrix(int node)
{
if(node == 0 || node > size)
{
std::cerr<<"There is no such a node!\n";
return false;
}
else
return true;
}
int MatrixRep::countNeighbours(int node)
{
int count_non_zero = 0;
for(int i = 0; i != size; i++)
if(matrix[node-1][i] != 0)
count_non_zero++;
return count_non_zero;
}
representation.h
struct NodeContainer
{
int size;
int* array;
NodeContainer();
~NodeContainer();
void allocateMemoryAndSetSize(int);
};
class MatrixRep
{
int size;
NodeContainer neighbours;
int** matrix;
public:
MatrixRep(int);
~MatrixRep();
void convertDataToMatrixRep(int**);
NodeContainer returnNeighbours(int);
void deleteNeighboursIfAny();
bool checkIfNotBeyondMatrix(int);
int countNeighbours(int);
void setupMatrix();
void deleteMatrix();
};
If you would like to return a copy of NodeContainer, you must implement a copy constructor and assignment operator for it. If you're using a C++11 conformant compiler it will also be good to also implement a move constructor and move assignment operator as well.
On the other hand, if you would like to not create a copy, you must either return a pointer or a reference to the member. You could also make the member a std::shared_ptr, which you may return in this case.
However, in your current implementation you're actually returning a shallow copy of NodeContainer. Once your copy goes out of scope its destructor is called, which deallocates its memory, which in this case is the original memory of your member, effectively making your member invalid. The implementation is not good as it is. So, depending on your goal, either implement the first advised solution, or the second.

Expand and add a new object to a array inside a function

I'm trying to expand and add a new object to a array inside a function and have that array be effected outside the function as well (the arrays pointer is sent as a parameter).
void addMedia(Media* medias[], int &nrOfMedias, string title, int publYear, string author, int nrOfPages)
{
Media** tempArray = new Media*[nrOfMedias +1];
for(int i = 0; i < nrOfMedias; i++)
{
tempArray[i] = medias[i];
}
delete [] medias;
medias = tempArray;
delete [] tempArray;
medias[nrOfMedias] = new Book(title, publYear, author, nrOfPages);
nrOfMedias++;
}
This code works great inside the function but when I get outside it the array is still empty. As i understand this it's because the pointer is changed inside the function but how can i expand the array without having it change the pointer?
(I can not change the return data type or the parameters, assignment requirements.)
Do change medias = tempArray; to *medias = tempArray;, make it compile, polish your memory management (consider, what really should be freed, what not).
Don't view medias as an array of pointers, view it as a pointer to an array. Working example (slightly simplified):
class Media
{
public:
Media () { m_strTitle = "unknown";}
string m_strTitle;
};
class Book : public Media
{
public:
Book(string strTitle) { m_strTitle = strTitle; }
};
void addMedia(Media* medias[], int &nrOfMedias)
{
Media * tempArray = new Media[nrOfMedias +1];
for(int i = 0; i < nrOfMedias; i++)
{
tempArray[i] = (*medias)[i];
}
delete [] *medias;
(*medias) = tempArray;
(*medias)[nrOfMedias] = Book("newTitle");
nrOfMedias++;
}
int main()
{
int numMedia = 10;
Media * myArray = new Media[numMedia];
addMedia(&myArray, numMedia);
for (int i = 0; i < numMedia; i++)
{
cout << i << ") " << myArray[i].m_strTitle << endl;
}
return 0;
}
You don't need delete [] tempArray; because tempArray actually points to the same memory block as medias does after medias = tempArray;
Your function will work well whithout that line but I assume that you know what you pass with Media* medias[]