I am testing an array template. It works fine for string type and int, but not for a typedef Student. I tried to figure out, but I can't find the problem. I did not use a separate compilation as it is just a test. I am using Dev-C++. Your help will be very appreciated. The code is below:
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
class Array
{
public:
Array(int initialSize);
~Array();
T & operator[](int i);
private:
T * m_pData;
int m_nSize;
};
//Implementing member functions in the Array template
template <typename T>
Array <T>::Array(int initialSize)
{
m_nSize = initialSize;
m_pData = new T [m_nSize];
};
template <typename T>
T & Array <T>::operator[](int i)
{
return m_pData[i];
};
template <typename T>
Array <T>::~Array()
{
delete[] m_pData;
};
typedef struct Student{}students[0];
//test array class implementatition
int main()
{
//creating an array of 20 integers, then assigning the value 50 at index 2
Array <int> myArray (20);
myArray[2] = 50;
cout << myArray[2] <<endl;
//creating an array of string of size 10, then assigning the string "Fred" at index 5
//then display the string
Array <string> nameArray (10);
nameArray[5] = string("Fred");
cout << nameArray[5] <<endl;
//creating an array of Student of size 100, then assigning the value "123456789" at index 4
//then display the value at that index
Array <Student> students (100);
students[4] = Student("123456789"); //here is the problem!!!
///cout << students[4] <<endl;
system ("pause");
return 0;
}
Student doesn't have a constructor,you can't call Student("123456789"); Try to define a constructor for Student:
struct Student
{
Student(): age_(0), name_("") {}
Student(int age): age_(age), name_("") {}
Student(const std::string& name): name_(name){
}
int age_;
std::string name_;
};
Related
I am having trouble with using the priority_queue in C++, I have a vector of priority queues, the priority queues contains several Person objects. Now I would like for the priority_queue to prioritize the Person objects based on their age. So I have something like this:
class Person
{
public:
string name;
int height;
int age;
};
std::vector<std::priority_queue<Person*>> Persons;
How do I make sure that whenever a person is added to one of the priority queues, that they are prioritized based on their age? And how would I do it in ascending/descending order?
You actually don't need the additional vector which wraps your priority_queue as the priority_queue itself has 2 additional default arguments:
(first one is the type, in your case Person*), second one is the container type and the third one is the compare predicate.
below you can see using a lambda function as a compare predicate for your priority queue.
#include <vector>
#include <string>
#include <queue>
#include <iostream>
using namespace std;
class Person
{
public:
string name;
int height;
int age;
Person(string n, int h, int a): name(n), height(h), age(a) {}
};
ostream& operator<<(ostream &cout, const Person* p) {
return cout << p->name << " height=" << p->height << " age=" << p->age << " ";
}
int main()
{
auto cmp = [](const Person* pl, const Person* pr) {
return (pl->age < pr->age);
};
priority_queue<Person*, vector<Person*>, decltype(cmp)> persons(cmp);
persons.push(new Person("a", 100, 10));
persons.push(new Person("b", 120, 20));
persons.push(new Person("c", 110, 15));
while (!persons.empty()) {
cout << persons.top() << endl;
persons.pop();
}
return 0;
}
You can pass a predicate as third parameter to detect sort order, declare two predicates for your Person*
struct AscendingPersonPredicate
{
bool operator() ( Person* p1, Person* p2) const
{
return p1->age < p2->age;
}
};
struct DescendingPersonPredicate
{
bool operator() ( Person* p1, Person* p2) const
{
return p1->age > p2->age;
}
};
Then declare your vector as:
std::priority_queue<Person*, vector<Person*>, AscendingPersonPredicate> Persons;
or
std::priority_queue<Person*, vector<Person*>, DescendingPersonPredicate> Persons;
std::priority_queue has an interface for what you require. It takes three template parameters:
template<
class T,
class Container = std::vector<T>,
class Compare = std::less<typename Container::value_type>
> class priority_queue;
The third one is what you need to change to handle the comparison of elements.
// make a functor to do the comparisons
struct comparator
{
bool operator()(Person* lhs, Person* rhs) const {
// sort by age
return lhs->age < rhs->age; // switch the sign for reverse order
}
};
// have a type alias for convenience (typedef is fine too)
using pqueue = std::priority_queue<Person*, std::vector<Person*>, comparator>;
int main()
{
std::vector<pqueue> persons;
}
You can implement like this :
#include <iostream>
#include <queue>
#include <vector>
#include <string>
using namespace std;
class Person
{
public:
string name;
int height;
int age;
};
struct OrderByAge
{
bool operator() (Person const &a, Person const &b) { return a.age > b.age; }
};
int main()
{
vector<priority_queue<Person, std::vector<Person>,OrderByAge> > personPQVec{ 1 };
Person p1{ "nitendra",5,39 };
Person p2{ "bhosle",6,34 };
Person p3{ "nit",4,33 };
personPQVec[0].push(p1);
personPQVec[0].push(p2);
personPQVec[0].push(p3);
while (!personPQVec[0].empty()) {
cout << "Name: " << (personPQVec[0]).top().name << ", age: " << (personPQVec[0]).top().age << endl;
(personPQVec[0]).pop();
}
system("pause");
return 0;
}
I want the bag class to have an array of item objects that is dynamically allocated but not sure how to do this. Also need someone to have a look at the rest of my code. I want to add Item objects to a Bag object and perform operations on the thus formed ADT as is evident from the code.
Item.h
#ifndef ITEM_H
#define ITEM_H
class Item
{
char* item_name;
public:
Item(char *name);
void display_item(Item i);
~Item();
protected:
private:
};
#endif
Item.cpp
#include "Item.h"
#include<string.h>
#include<iostream>
#include<malloc.h>
using namespace std;
Item::Item(char* name)
{
item_name = new char[sizeof(name)];
strcpy(item_name,name);
}
void Item::display_item(Item i)
{
cout<<i.item_name<<" ";
}
Item::~Item()
{
}
Bag.h
#include "Item.h"
#ifndef BAG_H
#define BAG_H
class Bag
{
int no_of_items;
int capacity;
Item list[];
public:
Bag(int no_of_items);
void add(Item i);
void display();
~Bag();
protected:
private:
};
#endif
Bag.cpp
#include "Bag.h"
#include "Item.h"
#include<malloc.h>
Bag::Bag(int capacity)
{
Item list[capacity];
no_of_items =0;
}
void Bag::add(Item i)
{
if(no_of_items<capacity)
{
list[no_of_items] = i;
no_of_items++;
}
else
{
cout<<"bag is full";
}
}
void Bag:: display()
{
for(i=0;i<no_of_items;i++)
{
display_item(list[i]);
}
}
Bag::~Bag()
{
//dtor
}
I'll not speak on your code, if you have problems with it, ask in a separate question with minimal code to reproduce the error. Here is a link, at the end of this answer, explaining how to dynamically allocate memory for your array. If you are doing so because you need a variable sized array, I would recommend a vector. While an object of type array must have the size defined at compile time, a vector does not have this requirement, and you can use vector_pushback to add new elements with ease. But if you insist on using an array, follow the instructions here: http://www.cplusplus.com/forum/articles/416/
As possible, always use STL containers. They have analogous interface and are well documented. Most of them are dynamic. So, your code with STL containers (std::string and std::vector) could look like:
#include <string>
#include <vector>
#include <iostream>
class Item {
public:
Item(const std::string& name) : item_name(name) {}
virtual ~Item() {}
void display_item() {
std::cout << item_name << " ";
}
private:
std::string item_name;
};
class Bag {
public:
void add(const Item& i) {
items.push_back(i);
}
void display() {
for(std::vector<Item>::iterator it = items.begin();
it != items.end(); ++it)
it->display_item();
}
private:
std::vector<Item> items;
};
As your question is aiming on how to implement your example with dynamic allocation, the code above without STL containers can be done as:
#include <cstring>
#include <algorithm>
#include <iostream>
class Item {
public:
Item() : item_name(0) {} // required for new[] expression
Item(const char* name) : item_name(0) {
copyName(name);
}
virtual ~Item() {
delete[] item_name; // don't forget to free the allocated memory
}
void display_item() const {
std::cout << item_name << " ";
}
Item& operator=(const Item& other) { // required for copying
copyName(other.item_name);
return *this;
}
private:
void copyName(const char* str) {
// get the size of the new name and delete the actual name
const size_t name_size = strlen(str);
delete[] item_name;
// allocate memory for new name and copy it
item_name = new char[name_size + 1]; // extra place for '\0'
strcpy(item_name, str);
}
char* item_name;
};
class Bag {
public:
Bag(size_t cap = 0) :
items(cap ? new Item[cap] : 0), capacity(cap), size(0) {}
virtual ~Bag() {
delete[] items;
}
void add(const Item& i) {
// "resize" the actual array if there is no space for a new item
if(size == capacity) {
// allocate new array and copy the actual content
capacity += 100;
Item* temp = new Item[capacity];
std::copy(items, items + size, temp);
// delete the actual array and assign the newly allocated one
delete[] items;
items = temp;
temp = 0;
}
// add the new item
items[size] = i;
size++;
}
void display() {
for(size_t i = 0; i < size; ++i)
items[i].display_item();
}
private:
Item* items;
size_t capacity;
size_t size;
};
Right now I am trying to make my template class and functions run but I am not sure how to define a template void function. Here's a small part of my code attached below. The code doesn't run and for anytime in the class arrayList is used it says argument list for arrayList is missing.
#include <iostream>
using namespace std;
template<typename Type> //Template class declaration
class arrayList
{
public:
void print() const;
protected:
int *list; //array to hold the list elements
int length; //to store the length of the list
int maxSize; //to store the maximum size of the list
};
template<typename Type>
void arrayList::print() const
{
int i;
for(i = 0; i < length; i++)
cout<<list[i]<<" ";
cout<<endl;
}
Try
template<typename Type>
void arrayList<Type>::print() const ...
There are a lecture class and student class. We are trying to save student information on lecture class with arrays.
For example:
Student * studentList = new Student[numberOfStudent];
studentAdd("Mary");
studentDelete("Mary");
Problem:
User is not giving number of student and number of student is increasing when user add a new one with a one of lecture method. So I think that i need a list like structer to save them but it is forbidden for this work. Do you have any efficient ideas than my temporary solution?
My temporary solution:
Saving number of student and array size and when number of student is more than size copy array to a new one which is bigger than old one.
This question is related to my assigment which we are forcing to this by
*using dynamically allocated memory using pointers
*without using any static arrays with fixed sizes or other data structures such as
vector from the standard library
you could just use functions if you don't want to use objects. Note that I haven't compiled this code.
#include <iostream>
#include <sstream>
#include <string>
#include "Student.h"
void add(Student **list, Student *rhs);
void destroy(Student **list,int const &idx);
void destroy(Student **list,const char* student_name); //find the student name and delete
void resize(Student **list,int const &idx);
Student** begin(Student **list,); //get the first Student
Student** end(Student **list,); //the end of the array
void clear(Student **list,); //drop all Students
int main(int argc, char **argv)
{
if(argc < 2)
{
stc::cerr << "not enough parameters" << std::endl;
}
istringstream buffer(argv[1]);
int value;
buffer >> value;
Student ** studentList = new *Student[value];
int s
add(studentList, "Mary");
destroy(studentList, "Mary");
return(0);
}
void add(Student **list, Student *rhs) { /*definition*/ }
void destroy(Student **list, int const &idx) { /*definition*/ }
void destroy(Student **list, const char* student_name) { /*definition*/ }
void resize(Student **list, int const &idx) { /*definition*/ }
Student** begin(Student **list) { /*definition*/ }
Student** end(Student **list) { /*definition*/ }
void clear(Student **list) { /*definition*/ }
Now just define all that and you are all set
I do not recommend this approach
I would use objects... and taking into account what PaulMcKenzie said about capacity
class StudentList
{
private:
Student **list;
std::size_t size;
std::size_t capacity;
public:
StudentList(){}
~StudentList(){ this->clear(); }
inline void add(Student *rhs) { //definition }
inline void destroy(int const &idx) { //definition }
inline void destroy(const char* student_name) { //definition }
inline void resize(int const &idx) { //definition }
inline Student** begin() { //definition }
inline Student** end() { //definition }
inline void clear() { //definition }
};
And if possible
Iterators
Underneath vector you will find a similar implementation, it uses Iterators to encapsulate the Student**.
I have the following code I was writing to test template specialization. Is there a way to have the pointer decay to the type so that I can use template parameter deduction to get my M and N so I can have the rows and cols of the two dimensional array? I know I can vector of vector for a 2d array, but this is an exercise in template specialization. The following code works as is, but see if you uncomment the following and comment out the current T** constructor it doesn't work. As a result the constructor currently hard codes the number of rows to be used for deleting the data_ member, this is not ideal and ideally I would get this parameter from the template deduction. I was wondering if there is a way to make this work in the following code shown below.
//doesn't like this constructor
// template <unsigned int M, unsigned int N>
// Data ( T (&d)[M][N] ): data_(d), rows_(M), cols_(N) {};
#include <iostream>
template <typename T>
class Data
{
public:
Data ( const T& d ): data_(d) {};
Data ( T&& d ): data_(std::move(d)) {};
std::string getType() { return "Plain Data Type"; }
private:
T data_;
};
template <typename T>
class Data<T**>
{
public:
//doesn't like this constructor
// template <unsigned int M, unsigned int N>
// Data ( T (&d)[M][N] ): data_(d), rows_(M), cols_(N) {};
Data ( T** d ): data_(d), rows_(25) {};
~Data() {
for ( unsigned int i = 0; i < rows_; ++i)
{
delete [] data_[i];
}
delete [] data_;
}
std::string getType() { return "Pointer to Pointer Data Type"; }
private:
T** data_;
unsigned int rows_;
unsigned int cols_;
};
template <typename T>
class Data<T*>
{
public:
Data ( T* d ): data_(d) {};
~Data() { delete data_; }
std::string getType() { return "Pointer Data Type"; }
private:
T* data_;
};
int main ( int argc, char *argv[])
{
float f(9.65);
Data<int> d1(f);
std::cout << d1.getType() << std::endl;
int *i = new int(5);
Data<int*> d2(i);
std::cout << d2.getType() << std::endl;
int **j = new int*[25];
for ( int i = 0 ; i < 25; ++i)
j[i] = new int[50];
Data<int**> d3(j);
std::cout << d3.getType() << std::endl;
}
output:
Plain Data Type
Pointer Data Type
Pointer to Pointer Data Type
T** and T[n][m] are not equivalent (and I curse the collegiate professors that refuse to teach this). One is a pointer-to-pointer, the other is an array of T[m] of size n.
You can specialize your 2D array type like this:
template<typename T, size_t N, size_t M>
class Data<T[N][M]>
{
public:
Data(const T(&ar)[N][M])
{
for (size_t i=0;i<N;++i)
std::copy(std::begin(ar[i]), std::end(ar[i]), std::begin(data[i]));
}
std::string getType() { return "2D-Fixed Array Data Type"; }
private:
T data[N][M];
};
And one way to use it is like this:
float fdat[10][20];
Data<decltype(fdat)> d4(fdat);
std::cout << d4.getType() << std::endl;
Output
2D-Fixed Array Data Type