Variadic parameters get does not work - c++

I am creating CPP application that can create List's: string arrays. When initialization is called it get's variadic parameters and should insert them into a string array. It gives Segmentation error. Also if I remove Students_Second_Group.push(), everything works fine. Any suggestions?
// Main.cpp
#include "List.h"
int main() {
List Students_First_Group(4), Students_Second_Group(3);
Students_First_Group.push("Jonas Jonaits", "Tomas Tomaitis", "Petras Petraitis", "Donatas Petkevicius");
Students_Second_Group.push("Mantas Jonaitis", "Tautvydas Tomaitis", "Linas Linaitis");
return 0;
}
// List.h
#ifndef _LIST_H_
#define _LIST_H_
#include <iostream>
#include <string>
#include <vector>
#include <cstdarg>
using namespace std;
class List {
private:
size_t size;
vector<string> arr;
public:
List(int size);
void push(const char* str...);
~List();
};
#endif
// List.cpp
#include "List.h"
List::List(int s) {
if(size > 0)
size = s;
else
size = 10;
arr = vector<string> (s);
}
void List::push(const char* str...) {
va_list arg;
va_start(arg, str);
while (str) {
arr.push_back(str);
str = va_arg(arg, const char *);
}
va_end(arg);
}
List::~List() {}

you can solve your issue with varadic template but
because they are template varadic template should be put in the header
for more info http://en.cppreference.com/w/cpp/language/parameter_pack
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class List {
private:
size_t size;
vector<string> arr;
void push() {}
public:
List(int size);
template<typename ... Rest>
void push(const char* first, Rest ... rest) {
arr.push_back(first);
push(rest...);
}
~List();
};
List::List(int s) {
if(size > 0)
size = s;
else
size = 10;
arr = vector<string> (s);
}
List::~List() {}
int main() {
List Students_First_Group(4), Students_Second_Group(3);
Students_First_Group.push("Jonas Jonaits", "Tomas Tomaitis", "Petras Petraitis", "Donatas Petkevicius");
Students_Second_Group.push("Mantas Jonaitis", "Tautvydas Tomaitis", "Linas Linaitis");
return 0;
}

Related

Inheriting from a template class in c++, fail to compile

My question is that, I have a template class template<class T> AList as base, and I wanna get a derived class from the template, i.e. get class BList: public AList<mydefinedtype> without much modification.
alist.h
#ifndef alist_h
#define alist_h
template<class T> class AList
{
public:
AList(){
arr = new T[20];
numitems = 0;
};
void append(T value);
private:
T *arr;
int numitems;
};
#endif /* alist_h */
alist.cpp
#include "alist.h"
template<class T> void AList<T>::append(T value)
{
arr[numitems] = value;
++numitems;
return;
}
blist.h
#include "alist.cpp"
#include <string>
using namespace std;
typedef struct
{
string a, b;
int key;
} record;
class BList: public AList<record>{
public:
void test(void){
cout << "this is from BList" << endl;
}
};
blist.cpp
#include "blist.h"
main.cpp
#include <iostream>
#include "blist.cpp"
using namespace std;
int main(){
record testRecord[3];
testRecord[0] = {"Mark", "A", 1};
testRecord[1] = {"Anla", "B", 2};
testRecord[2] = {"Cindy", "C", 3};
BList blist = BList();
for(auto i: testRecord){
// blist.append(i); // will compile error
blist.test();
}
return 0;
}
It will fail as follows, I wonder how to compile or how to fix the bug.
error info
Undefined symbols for architecture x86_64:
"AList<record>::append(s)", referenced from:
_main in main.o
ld: symbol(s) not found for architecture x86_64
Not sure where comes from the issue.
// Example program
#include <iostream>
#include <string>
struct record{
int a;
};
template<class T>
class AList{
public:
AList()=default;
void append(T value){}
};
template<class T>
class BList:public AList<T>{
public:
void test(void){}
};
int main()
{
BList<record> blist;
record recordarr[3] ;
// some initialization
for(auto i:recordarr){
blist.append(i);
blist.test();
}
}
The problem you have is that the AList() constructor, append(T) and test() are only declared but not defined. The above code should compile.
You should put your template classes entirely in header files. See this question and this C++ FAQ for details on why.
You should also never #include .cpp files. You should only ever #include header files.
Below I have your code after the required modifications to make it compile. I also removed your memory leak.
alist.h:
#ifndef alist_h
#define alist_h
template<class T> class AList {
public:
AList() {
arr = new T[20];
numitems = 0;
};
~AList() {
delete[] arr;
}
void append(T value) {
arr[numitems] = value;
++numitems;
}
private:
T *arr;
int numitems;
};
#endif /* alist_h */
blist.h:
#ifndef blist_h
#define blist_h
#include "alist.h"
#include <string>
using namespace std;
typedef struct {
string a, b;
int key;
} record;
class BList: public AList<record> {
public:
void test(void) {
cout << "this is from BList" << endl;
}
};
#endif /* blist_h */
main.cpp:
#include <iostream>
#include "blist.h"
using namespace std;
int main() {
record testRecord[3];
testRecord[0] = {"Mark", "A", 1};
testRecord[1] = {"Anla", "B", 2};
testRecord[2] = {"Cindy", "C", 3};
BList blist = BList();
for (auto i: testRecord) {
blist.append(i);
blist.test();
}
return 0;
}
Summary of changes
I made the following changes:
Moved body of AList::append into alist.h, and deleted alist.cpp
Added AList destructor to free the dynamically allocated memory allocated in AList::AList
In blist.h, included alist.h instead of alist.cpp
Deleted blist.cpp
In main.cpp, included blist.h instead of blist.cpp

C++ : Error Redefinition & Previously Declared

I am half way into my course.I am unable to understand the logic behind the errors I am receiving. I have already tried to counter it by using appropriate directives at the bottom of my Array.h file. I am receive the following 2 errors across all functions:
note: 'const T& udbhavAg::Container::Array::operator const' previously declared here
const T &Array::operator[](int index) const {
error: redefinition of 'const T& udbhavAg::Container::Array::operator const'
const T &Array::operator[](int index) const {
My questions are the following :
Why are the files being declared twice?
Why are they being redefined?
Main.cpp
#include <iostream>
#include "Point.h"
#include "Line.h"
#include "Circle.h"
#include "Array.h"
#include "ArrayException.h"
using namespace std;
using namespace udbhavAg::CAD;
using namespace udbhavAg::Container;
using namespace udbhavAg;
int main()
{
Array<Point> points(10);
return 0;
}
Array.h
#include "Point.h"
#include <cstring>
#include "ArrayException.h"
#ifndef ARRAY_H
#define ARRAY_H
//#include "Array.cpp"
namespace udbhavAg
{
namespace Container
{
template <typename T>
class Array {
private:
T *m_data;
int m_size;
public:
Array();
Array(int size);
Array(const Array &obj);
virtual ~Array();
//const Array operator= ( const Array & source);
Array<T> &operator=(const Array &source);
int Size() const;
void setElement(int index, T p);
T &getElement(int index) const;
T &operator[](int index);
const T &operator[](int index) const;
};
}
}
#ifndef Array_cpp // Must be the same name as in source file #define
#include "Array.cpp"
#endif
#endif ARRAY_H
Array.cpp
#include "Array.h"
#include "ArrayException.h"
namespace udbhavAg
{
namespace Container
{
template<typename T>
Array<T>::Array():m_size(3),m_data(new T[m_size]) {}
template<typename T>
Array<T>::Array(int size): m_size(size), m_data(new T[m_size]) {}
template<typename T>
Array<T>::~Array()
{
delete[] m_data;
cout << "Destructor called" << endl;
}
template<typename T>
Array<T>::Array(const Array &obj) {
m_size = obj.m_size;
m_data = new CAD::Point[m_size];
for (int i = 0; i < m_size; i++)
{
m_data[i] = obj.operator[](i);
}
}
template<typename T>
int Array<T>::Size() const
{
return m_size;
}
template<typename T>
T &Array<T>::getElement(int index) const
{
try
{
if (index >= m_size || index < 0)
{
throw (OutofBoundsException(index));
}
else
{
return m_data[index];
}
}
catch (ArrayException &error)
{
cout << error.GetMessage();
}
}
template<typename T>
void Array<T>::setElement(int index, T p)
{
try
{
if (index >= m_size || index < 0)
{
// OutofBoundsException error = OutofBoundsException(index);
// ArrayException& abc = error;
throw (OutofBoundsException(index));
}
else
{
m_data[index] = p;
}
}
catch (ArrayException &error)
{
cout << error.GetMessage();
}
}
template<typename T>
Array<T> & Array<T>::operator=(const Array &source)
{
if(&source != this){ //edited self assignment test
if(m_size != source.m_size){//diff sized arrays
delete [] m_data; //reclaim space
m_size = source.m_size;
m_data = new CAD::Point[m_size]; //space created
}
}
for(int i=0; i<m_size; i++){
m_data[ i ] = source.m_data[i];}
return *this; //enables cascading a=b=c
}
template<typename T>
T &Array<T>::operator[](int index) {
try
{
if (index >= m_size || index < 0)
{
// OutofBoundsException error = OutofBoundsException(index);
// ArrayException& abc = error;
throw (OutofBoundsException(index));
}
else
{
return m_data[index];
}
}
catch (ArrayException &error)
{
cout << error.GetMessage();
}
}
template<typename T>
const T &Array<T>::operator[](int index) const {
try
{
if (index >= m_size || index < 0)
{
// OutofBoundsException error = OutofBoundsException(index);
// ArrayException& abc = error;
throw (OutofBoundsException(index));
}
else
{
return m_data[index];
}
}
catch (ArrayException &error)
{
cout << error.GetMessage();
}
}
}
}
probably because in Array.h :
#ifndef Array_cpp // Must be the same name as in source file #define
#include "Array.cpp"
#endif
so Array.cpp #include Array.h whose #include Array.cpp because Array_cpp is not defined
Do not include source file in your header files
Out of that why in Array.h
#ifndef ARRAY_H
#define ARRAY_H
is not at the beginning of the file ?
So possible exclusive solutions to solve are :
to remove #include "Array.h" at the beginning of Array.cpp
to add #define Array_cpp to be the very first line in Array.cpp
in both case you must not compile Array.cpp in your Makefile or equivalent nor link with it.
But the best one is to replace in Array.h
#ifndef Array_cpp // Must be the same name as in source file #define
#include "Array.cpp"
#endif
by the definitions from the file Array.cpp and to delete the file Array.cpp.
The template classes are special, all template methods must be defined in the header file and only in it, not in a source file also compiled as a 'normal' source file, the compiler does the stuff for you

Question with constructor in C++ ArrayStack

I am in the process of constructing a StackArray. I already have a "Stack.h" implemented with a constructor. I was wondering what I would do in my "StackArray.h" file to use the Stack.h file. I was thinking to use inheritance but it was giving me a error.
My code is as follows:
Array.h
#include <iostream>
#include <assert.h>
using namespace std;
#ifndef _ARRAY_H
#define _ARRAY_H
template<class T>
class Array{
private:
T *a;
int length;
public:
// constructor
Array (int len){
length = len;
a = new T[length];
for (int i = 0; i < len; i++){
a[i]=0;
}
}
// destructor
~Array()
{delete[] a;}
// operator overload
T& operator [](int i){
assert (i>=0 && i < length);
return a[i];
}
//get the length of the array
int arraylength(){
return length;
}
};
#endif
ArrayStack.h
#ifndef _ARRAYSTACK_H_
#define _ARRAYSTACK_H_
#include "Array.h"
using namespace std;
template<class T>
class ArrayStack
{
protected:
Array<T> a;
int n;
public:
ArrayStack(int len);
virtual ~ArrayStack();
};
template<class T>
ArrayStack<T>::ArrayStack(int len){
// I don't know what to do here to implemented constructor from another class.
}
#endif
Any suggestion would be great, Thank you
Andy

How to pass vector as reference in C++?

I want to pass my vector "myStaffs" from Team Class by reference to Manage Class because I want to manipulate the data of staffs and sort them. How do I pass it by reference?
Header Staff
#ifndef STAFF_H
#define STAFF_H
#include <vector>
#include <cstdlib>
#include <ctime>
#include <string>
class Staff
{
public:
Staff();
Staff(int, int, int, int);
~Staff();
static int genRanNum(int);
static Staff* createStaff(int);
const int getSize();
private:
int staSkills1,staSkills2,staSkills3;
int staId;
//int staDeptAsigned;
//std::string staName;
};
#endif
CPP Staff
#include "Staff.h"
#include <iostream>
using namespace std;
Staff::Staff():
staId(0),
staSkills1(0),
staSkills2(0),
staSkills3(0)
{
}
Staff::Staff(int id, int s1, int s2, int s3):
staId(id),
staSkills1(s1),
staSkills2(s2),
staSkills3(s3)
{
}
Staff *Staff::createStaff(int s)
{
Staff *staff = new Staff();
staff->staId = s;
staff->staSkills1 = genRanNum(10);
staff->staSkills2 = genRanNum(10);
staff->staSkills3 = genRanNum(10);
return staff;
}
int Staff::genRanNum(int num)
{
return 1+(rand()%num);
}
Staff::~Staff()
{
}
Header Team
#ifndef TEAM_H
#define TEAM_H
#include "Staff.h"
#include <vector>
#include <iostream>
using std::vector;
class Team: public Staff
{
public:
Team();
~Team();
private:
vector<Staff *> myStaffs;
};
#endif // TEAM_H
CPP Team
#include "Team.h"
const int SIZE = 30;
Team::Team():
myStaffs(SIZE)
{
for(int iStaff = 0; iStaff <= SIZE; iStaff++)
{
myStaffs[iStaff] = createStaff(iStaff);
}
}
Team::~Team()
{
}
Header Manage
#ifndef OPTIONS_H
#define OPTIONS_H
#include "Team.h"
#include <vector>
#include <iostream>
using std::vector;
class Manage
{
public:
Manage();
~Manage();
private:
// vector
};
CPP Manage
#include "Manage.h"
Manage::Manage()
{
}
Manage::~Manage()
{
}
#endif
Its simple you pass it as you would pass any other object by reference
int sortEmployee(std::vect<Staff *> &staffList> {
// ... code to sort Employee
}
and you can call it like below
vector<Staff *> myStaffs
result = sortEmployee(myStaffs);
It's as simple as
#include <vector>
void myVectorManglingFun(std::vector<Staff *> &myStaff) //notice the &
{
//do something here
}
If you don't need to modify the vector, then always use a const reference.
void myVectorReadingFun(const std::vector<Staff *> &myStaff)

PersonalVec.hpp:12: error: expected unqualified-id before ‘;’ token error

I got this error and I can't figure out why.
#include <vector>
#include <cstdlib>
#ifndef PERSONALVEC_HPP_
#define PERSONALVEC_HPP_
template <class T,class PrnT>
class PersonalVec
{
public:
PersonalVec() {}
~PersonalVec()
{
//TODO: delete vector.
}
void push_back(T& obj)
{
int index = rand()%_vec.size();
}
private:
vector<T*> _vec;
};
#endif /* PERSONALVEC_HPP_ */
Both rand and vector are in the std namespace.
Use
private:
std::vector<T*> _vec;
and
std::rand()
On this line:
int index = rand()%_vec.size();
You call the function rand() but do not include the header which declares it. Specifically, you need to add the following line to the top of your program:
#include <cstdlib>
Part of the problem is likely that you are using a vector without being in the std namespace. change vector<T*> _vec to std::vector<T*> _vec.
The following code (Ideone linky: http://www.ideone.com/HgL1e) seems to work fine.
#include <vector>
#include <cstdlib>
template <class T,class PrnT>
class PersonalVec
{
public:
PersonalVec() {}
~PersonalVec()
{
//TODO: delete vector.
}
void push_back(T& obj)
{
int index = rand()%_vec.size();
}
private:
std::vector<T*> _vec;
};
int main()
{
int i = 1;
PersonalVec<int, int> testVec;
testVec.push_back(i);
return 0;
}