I'm currently making a simulation of an autonomous car for my AI class. The car's constructor receives the board as a parameter so it can set the position of the car and add the first node to the search tree, so it can search an optimum path from the Starting Position to the Finishing Position. The thing is, the board generates without any problem, but when I try to pass it to the car's constructor, it results in a Segmentation fault (core dumped) error.
I used a debugger (gdb), ran the code in it and made a back-trace; and the problem came from here:
void node_c::add_child(node_c* chld)
{ int i;
for (i = 0; i < MAX_CHILDREN; i++)
{ if (children_[i] == NULL) //This line's the problem
break;
}
if (children_[i] != NULL)
{ cout << endl << "You can't add any more children." << endl;
return;
}
else children_[i] = chld;
}
Note: 'children_' contains a maximum of 4 children of a search_tree's node, and is a custom vector_c class I had to make.
This is the operator that fails and the function it calls:
template <typename TDato>
TDato& vector_c<TDato>::operator [](int position) { return get_data(position); }
template <typename TDato>
TDato& vector_c<TDato>::get_data(int a) const { return data_[a]; }
I thought that it might be a type error in the comparison if (children_[i] == NULL) so I made a custom operator that returned an object (TDato), not a reference to an object (TDato&), but it didn't work.
I can't imagine what could be causing this and/or how to solve it.
Thanks in advance.
Edit 1: Here's a google drive link to the project as even a minimal reproducible example would be too large to be easy to read in a Stack Overflow question. It's not very big, I promise (less than 1 MB).
Edit 2: Here's the most I could do to make the reproducible example minimal, as the question got closed for not including it.
main.cpp
#include "../include/board_s.hpp"
#include "../include/car_c.hpp"
using namespace std;
int main(void)
{ board_s<int> board(20, 20);
board.file_depiction();
car_c car(board);
board.write(cout);
return 0;
}
Here, the problem comes when the constructor of car_c is called. It should create an car_c object.
board_c.hpp
#ifndef __BOARD_S__
#define __BOARD_S__
#include <cstdio>
#include <iostream>
#include <cstring>
#include <random>
#include <fstream>
#include <utility>
#include "matrix_c.hpp"
#include "tree_c.hpp"
using namespace std;
template <typename TDato = int>
class board_s: public matrix_c<TDato>
{ private:
pair<int, int> starting_pos;
pair<int, int> finishing_pos;
public:
board_s(int, int);
~board_s(void);
pair<int, int> get_start(void);
void file_depiction(void); //Generates obstacles and starting/finishing points as depicted in board_depiction.txt.
virtual ostream& write(ostream&);
int distance(pair<int, int>&) const; //Returns the distance from a given position to the finishing point
private:
bool object_setter(string, int&, int&);
int object_identifier(string&) const; //Given the name of the object ("NEW OBSTACLE" [1], "STARTING POSITION" [2] or "FINISHING POSITION" [3]) returns it's code
};
template class board_s<int>;
#endif
board_c.cpp
#include "../include/board_s.hpp"
#include "matrix_c.cpp"
using namespace std;
//The constructor fills the board with empty boxes.
template <typename TDato>
board_s<TDato>::board_s(int m, int n):
matrix_c<TDato>::matrix_c(m + 2, n + 2)
{ for(int i = 1; i < m; i++)
for(int j = 1; j < n; j++)
matrix_c<TDato>::at(i, j) = 0;
for(int i = 0; i < n + 2; i++)
{ matrix_c<TDato>::at(0, i) = 1;
matrix_c<TDato>::at(m + 1, i) = 1;
}
for(int i = 0; i < m + 2; i++)
{ matrix_c<TDato>::at(i, 0) = 1;
matrix_c<TDato>::at(i, n + 1) = 1;
}
starting_pos.first = 0;
starting_pos.second = 0;
finishing_pos.first = 0;
finishing_pos.second = 0;
}
template <typename TDato>
board_s<TDato>::~board_s(void){}
template <typename TDato>
pair<int, int> board_s<TDato>::get_start(void) { return starting_pos; }
template <typename TDato>
void board_s<TDato>::file_depiction(void)
{ string line;
int x, y, i;
std::ifstream bd;
bd.open("board_depiction.txt");
if (bd.is_open())
{ getline(bd, line);
getline(bd, line);
i = line.size() - 1;
y = matrix_c<TDato>::strtoi(line, i);
i--;
x = matrix_c<TDato>::strtoi(line, i);
matrix_c<TDato>::resize(x + 2, y + 2);
getline(bd, line);
getline(bd, line);
i = line.size() - 1;
y = matrix_c<TDato>::strtoi(line, i);
i--;
x = matrix_c<TDato>::strtoi(line, i);
object_setter("STARTING POSITION", x, y);
getline(bd, line);
getline(bd, line);
i = line.size() - 1;
y = matrix_c<TDato>::strtoi(line, i);
i--;
x = matrix_c<TDato>::strtoi(line, i);
object_setter("FINISHING POSITION", x, y);
while (getline(bd, line))
if (line[0] != 'O')
{ i = line.size() - 1;
y = matrix_c<TDato>::strtoi(line, i);
i--;
x = matrix_c<TDato>::strtoi(line, i);
object_setter("NEW OBSTACLE", x, y);
}
}
else cout << "ERROR";
}
template <typename TDato>
ostream& board_s<TDato>::write(ostream& os)
{ int temp = matrix_c<TDato>::get_n() - 2 + (4 * (matrix_c<TDato>::get_n() - 2));
os << " ";
for (int i = 1; i < temp; i++)
os << "_";
os << " " << endl << "|";
for (int i = 1; i < matrix_c<TDato>::get_m() - 1; i++)
{ for (int j = 0; j < 2; j++)
{ for (int k = 1; k < matrix_c<TDato>::get_n() - 1; k++)
switch (matrix_c<TDato>::at(i, k))
{ case 1:
os << "████|";
break;
case 2:
if (j == 0)
os << " CC |";
else os << "_CC_|";
break;
case 3:
if (j == 0)
os << " FF |";
else os << "_FF_|";
break;
default:
if (j == 0)
os << " |";
else os << "____|";
}
os << endl;
if (j == 0) os << "|";
}
if (i < matrix_c<TDato>::get_m() - 2) os << "|";
}
os << endl;
return os;
}
template <typename TDato>
int board_s<TDato>::distance(pair<int, int>& pos) const
{ int d = (finishing_pos.first - pos.first) + (finishing_pos.second - pos.second);
if (d < 0) return (d * (-1));
else return d;
}
template <typename TDato>
bool board_s<TDato>::object_setter(string name, int &x, int &y)
{ if((x > 0) && (x < matrix_c<TDato>::get_m() - 1) && (y > 0) && (y < matrix_c<TDato>::get_n() - 1) && (matrix_c<TDato>::at(x, y) == 0))
{ matrix_c<TDato>::at(x, y) = object_identifier(name);
cout << endl << endl << "The " << name << " has been set in (" << x << ", " << y << ")" << endl;
if (name == "STARTING POSITION")
{ starting_pos.first = x;
starting_pos.second = y;
}
else if (name == "FINISHING POSITION")
{ finishing_pos.first = x;
finishing_pos.second = y;
}
return true;
}
else
{ cout << endl << "The coordinates that you intriduced were out of reach or the position wasn't free." << endl;
return false;
}
}
template <typename TDato>
int board_s<TDato>::object_identifier(string &name) const
{ if (name == "NEW OBSTACLE")
return 1;
else if (name == "STARTING POSITION")
return 2;
else if (name == "FINISHING POSITION")
return 3;
else return 0;
}
matrix_c.hpp
#ifndef __MATRIX_C__
#define __MATRIX_C__
#include <cstdio>
#include <iostream>
#include <iomanip>
#include <cstring>
#include "vector_c.hpp"
using namespace std;
template <typename TDato>
class matrix_c //Template matrix class implemented with a vector.
{ private:
int m_;
int n_;
vector_c<TDato> v_;
public:
matrix_c(void); //Empty constructor
matrix_c(int, int); //Constructor with dimensions
~matrix_c(void);
void resize(int, int);
TDato& at (int, int); //Redirects to position (x, y)
virtual TDato& operator()(int, int); //Operator for at(int, int)
int get_m(void) const;
int get_n(void) const;
private:
int pos(int, int);
protected:
int ctoi(char&) const;
int strtoi(string&, int&) const;
};
#endif
matrix_c.cpp
#include "../include/matrix_c.hpp"
using namespace std;
template <typename TDato>
matrix_c<TDato>::matrix_c(void):
m_(0),
n_(0),
v_() {}
template <typename TDato>
matrix_c<TDato>::matrix_c(int m, int n):
m_(m),
n_(n),
v_(m * n) {}
template <typename TDato>
matrix_c<TDato>::~matrix_c(void) {}
template <typename TDato>
void matrix_c<TDato>::resize(int m, int n)
{ v_.resize(m * n);
m_ = m;
n_ = n;
}
template <typename TDato>
TDato& matrix_c<TDato>::at(int i, int j) { return v_[(pos(i,j))]; }
template <typename TDato>
TDato& matrix_c<TDato>::operator()(int i, int j) { return at(i,j); }
template <typename TDato>
int matrix_c<TDato>::get_m(void) const { return m_; }
template <typename TDato>
int matrix_c<TDato>::get_n(void) const { return n_; }
template <typename TDato>
int matrix_c<TDato>::pos(int i, int j) { return ((n_ * i) + j); }
template <typename TDato>
int matrix_c<TDato>::ctoi(char &c) const
{ int n = c;
return n - 48;
}
template <typename TDato>
int matrix_c<TDato>::strtoi(string &s, int& i) const
{ int n = 0;
int mult = 1;
while ((s[i] != ' ') && (i >= 0))
{ n += ctoi(s[i]) * mult;
mult *= 10;
i--;
}
return n;
}
template class matrix_c<int>;
vector_c.hpp
#ifndef __VECTOR_C__
#define __VECTOR_C__
#include <iostream>
#include <cstdio>
#include <cassert>
using namespace std;
template <typename TDato>
class vector_c
{ private:
int sz_;
TDato* data_;
public:
vector_c(void); //Empty constructor
vector_c(int); //Constructor with size
~vector_c(void);
TDato& get_data(int) const;
void set_data(TDato&, int);
ostream& write(ostream&) const;
TDato& operator [](int);
void resize(int);
private:
void new_vector(void);
void del_vector(void);
};
#endif
vector_c.cpp
#include "../include/vector_c.hpp"
#include "../include/node_c.hpp"
using namespace std;
template <typename TDato>
vector_c<TDato>::vector_c(void):
sz_(0),
data_(NULL) {}
template <typename TDato>
vector_c<TDato>::vector_c(int size):
sz_(size),
data_(new TDato[sz_]) {}
template <typename TDato>
vector_c<TDato>::~vector_c(void)
{ delete[] data_;
data_ = NULL;
}
template <typename TDato>
TDato& vector_c<TDato>::get_data(int a) const { return data_[a]; }
template <typename TDato>
void vector_c<TDato>::set_data(TDato& dat, int a) { data_[a] = dat;}
template <typename TDato>
TDato& vector_c<TDato>::operator [](int position) { return get_data(position); }
template <typename TDato>
void vector_c<TDato>::resize(int sz)
{ del_vector();
sz_ = sz;
new_vector();
}
template <typename TDato>
void vector_c<TDato>::new_vector(void){
data_ = new TDato[sz_];
}
template <typename TDato>
void vector_c<TDato>::del_vector(void)
{ if (data_ != NULL){
delete [] data_;
data_ = NULL;
}
}
template class vector_c<int>;
template class vector_c<node_c*>;
node_c.hpp
#define MAX_CHILDREN 4
#ifndef __NODE_C__
#define __NODE_C__
#include <iostream>
#include <cstdio>
#include <cassert>
#include "vector_c.hpp"
using namespace std;
class node_c
{ private:
node_c* parent_;
vector_c< node_c* > children_;
pair<pair<int, int>, int> data_;
public:
node_c(void);
node_c(int &x, int &y, int &cost);
node_c(pair<pair<int, int>, int>&);
~node_c(void);
void add_child(node_c*);
};
#endif
node_c.cpp
#include "../include/node_c.hpp"
using namespace std;
node_c::node_c(void):
parent_(NULL)
{ for (int i = 0; i < MAX_CHILDREN; i++)
children_[i] = NULL;
data_.first.first = 0;
data_.first.second = 0;
data_.second = 0;
}
node_c::node_c(int &x, int &y, int &cost):
parent_(NULL)
{ for (int i = 0; i < MAX_CHILDREN; i++)
children_[i] = NULL;
data_.first.first = x;
data_.first.second = y;
data_.second = cost;
}
node_c::node_c(pair<pair<int, int>, int> &dat):
parent_(NULL),
data_(dat)
{ for (int i = 0; i < MAX_CHILDREN; i++)
children_[i] = NULL;
}
node_c::~node_c(void)
{ parent_ = NULL;
for (int i = 0; i < MAX_CHILDREN; i++)
children_[i] = NULL;
data_.first.first = 0;
data_.first.second = 0;
data_.second = 0;
}
void node_c::add_child(node_c* chld)
{ int i;
for (i = 0; i < MAX_CHILDREN; i++)
{ if (children_[i] == NULL)
break;
}
if (children_[i] != NULL)
{ cout << endl << "You can't add any more children." << endl;
return;
}
else children_[i] = chld;
}
tree_c.hpp
#ifndef __TREE_C__
#define __TREE_C__
#include "node_c.hpp"
using namespace std;
class tree_c
{ private:
node_c* root_;
int depth_;
public:
tree_c(void);
tree_c(node_c*);
node_c* add_node(node_c*, int&, int&, int);
};
#endif
tree_c.cpp
#include "../include/tree_c.hpp"
using namespace std;
tree_c::tree_c(void):
root_(NULL),
depth_(0) {}
tree_c::tree_c(node_c* root):
root_(root),
depth_(1) {}
node_c* tree_c::add_node(node_c* parent, int& x, int& y, int cost)
{ node_c* node = new node_c(x, y, cost);
parent->add_child(node);
}
car_c.hpp
#ifndef __CAR_C__
#define __CAR_C__
#include <iostream>
#include <cstdio>
#include <cassert>
#include "tree_c.hpp"
#include "board_s.hpp"
using namespace std;
class car_c
{ private:
tree_c tree_;
pair<int, int> pos_;
matrix_c<int> visited_;
public:
car_c(void);
car_c(board_s<int>&);
~car_c(void);
};
#endif
car_c.cpp
#include "../include/car_c.hpp"
using namespace std;
car_c::car_c(void):
tree_(NULL)
{ pos_.first = 0;
pos_.second = 0;
}
car_c::car_c(board_s<int>& board):
pos_(board.get_start()),
tree_(tree_.add_node(NULL, pos_.first, pos_.second, 0))
{ visited_(pos_.first, pos_.second) = 1; }
car_c::~car_c(void) {}
Debugging information:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000401cc2 in node_c::node_c (this=0x6187d0, x=#0x7ffffffeddf0: 8, y=#0x7ffffffeddf4: 0,
cost=#0x7ffffffedd2c: 0) at src/node_c.cpp:20
20 children_[i] = NULL;
(gdb) bt
#0 0x0000000000401cc2 in node_c::node_c (this=0x6187d0, x=#0x7ffffffeddf0: 8, y=#0x7ffffffeddf4: 0,
cost=#0x7ffffffedd2c: 0) at src/node_c.cpp:20
#1 0x0000000000402007 in tree_c::add_node (this=0x7ffffffedde0, parent=0x0, x=#0x7ffffffeddf0: 8,
y=#0x7ffffffeddf4: 0, cost=0) at src/tree_c.cpp:16
#2 0x0000000000402df6 in car_c::car_c (this=0x7ffffffedde0, board=...) at src/car_c.cpp:15
#3 0x0000000000401403 in main () at src/main.cpp:11
Sorry for the length of my question, but this is the minimal reproducible example I was able to make. If you know another way to recreate my error, let me know so I can improve this.
I would like some guidance on a program I am working on currently, I have successfully created a pair of integers and handled exception if the user were to enter the same values twice. I am stuck on doing the same process of creating pairs but instead of ints it has to be strings.
One suggestion that I have is changing the random generation of ordered pairs with:
string empty = "";
myList2[i].setFirst(empty + char('a' + rand() % 26));
myList2[i].setSecond(empty + char('A' + rand() % 26));
Any suggestions in the right direction would be appreciated.
Client File:
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <exception>
#include "orderedpair.h"
using namespace std;
using namespace cs_pairs;
int main() {
int num1, num2;
OrderedPair<int> myList[10];
srand(static_cast<unsigned>(time(0)));
cout << "default value: ";
myList[0].print();
cout << endl;
for (int i = 0; i < 10; i++) {
myList[i].setFirst(rand() % 50);
myList[i].setSecond(rand() % 50 + 50);
}
myList[2] = myList[0] + myList[1];
if (myList[0] < myList[1]) {
myList[0].print();
cout << " is less than ";
myList[1].print();
cout << endl;
}
for (int i = 0; i < 10; i++) {
myList[i].print();
cout << endl;
}
cout << "Enter two numbers to use in an OrderedPair. Make sure they are different numbers: ";
cin >> num1 >> num2;
OrderedPair<int> x;
/* use this before you've implemented the exception handling in the class:
x.setFirst(num1);
x.setSecond(num2);
*/
/* use this after you've implemented the exception handling in the class: */
try {
x.setFirst(num1);
x.setSecond(num2);
/*if (x.setFirst(num1) == x.setSecond(num2))
{
throw OrderedPair<int>::DuplicateMemberError;
} */
}
catch (OrderedPair<int>::DuplicateMemberError e) {
cout << "YOU ENTERED TWO OF THE SAME VALUES!" << endl;
x.setFirst(OrderedPair<int>::DEFAULT_VALUE);
x.setSecond(OrderedPair<int>::DEFAULT_VALUE);
}
cout << "The resulting OrderedPair: ";
x.print();
cout << endl;
}
Header File:
#ifndef ORDEREDPAIR_H
#define ORDEREDPAIR_H
#include <iostream>
namespace cs_pairs
{
template <class T>
class OrderedPair
{
public:
typedef std::size_t size_type;
typedef T value_type; // changed int to T
static const int DEFAULT_VALUE = 0;
class DuplicateMemberError
{
};
OrderedPair(T newFirst = DEFAULT_VALUE, T newSecond = DEFAULT_VALUE);
void setFirst(T newFirst);
void setSecond(T newSecond);
T getFirst() const;
T getSecond() const;
OrderedPair<T> operator+(const OrderedPair<T>& right) const;
bool operator<(const OrderedPair<T>& right) const;
void print() const;
private:
T first;
T second;
};
}
#include "orderedpair.cpp"
#endif // !ORDEREDPAIR_H
Implementation File:
#include <iostream>
#include <exception>
using namespace std;
namespace cs_pairs
{
template <class T>
OrderedPair<T>::OrderedPair(T newFirst, T newSecond) {
setFirst(newFirst);
setSecond(newSecond);
}
template <class T>
void OrderedPair<T>::setFirst(T newFirst) {
if ((newFirst == second) && (newFirst != 0))
{
throw DuplicateMemberError();
}
first = newFirst;
}
template <class T>
void OrderedPair<T>::setSecond(T newSecond) {
if ((newSecond == first) && (newSecond != 0))
{
throw DuplicateMemberError();
}
second = newSecond;
}
template <class T>
T OrderedPair<T>::getFirst() const {
return first;
}
template <class T>
T OrderedPair<T>::getSecond() const {
return second;
}
template <class T>
OrderedPair<T> OrderedPair<T>::operator+(const OrderedPair<T>& right) const {
return OrderedPair(first + right.first, second + right.second);
}
template <class T>
bool OrderedPair<T>::operator<(const OrderedPair<T>& right) const {
return first + second < right.first + right.second;
}
template <class T>
void OrderedPair<T>::print() const {
std::cout << "(" << first << ", " << second << ")";
}
}
To be generic, get rid of static const int DEFAULT_VALUE = 0;
Get rid of default constructor which doesn't respect your invariant
I would get rid of individual setter which might be problematic when uses together:
void swap_order(OrderedPair<int>& op)
{
const auto first = op.getFirst();
op.setFirst(op.getSecond()); // Oups... throw exception
op.setSecond(first);
}
So:
template <class T>
class OrderedPair
{
public:
using size_type = std::size_t;
using value_type = T;
class DuplicateMemberError{};
OrderedPair(const T& newFirst, const T& newSecond) : first(newFirst), second(newSecond) { check(); }
const T& getFirst() const { return first; }
const T& getSecond() const { return second; }
OrderedPair<T> operator+(const OrderedPair<T>& right) const;
bool operator<(const OrderedPair<T>& rhs) const;
void print() const;
private:
void check() { if (first == second) throw DuplicateMemberError{}; }
private:
T first;
T second;
};
As no longer default constructible, you have to change
OrderedPair<int> myList[10]; by
std::vector<OrderedPair<int>> myList; /*myList.reserve(10);*/
and generation would be:
//const std::string empty;
const char lower_alphabet = "abcdefghijklmnopqrstuvwxyz"; // 'a'-'z' is not guaranty to be contiguous (EBCDIC)
const char upper_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // 'A'-'Z' is not guaranty to be contiguous (EBCDIC)
for (int i = 0; i < 10; i++) {
myList.emplace_back(rand() % 50, rand() % 50 + 50);
// myList.emplace_back(empty + char(lower_alphabet[rand() % 26], empty + char(upper_alphabet[rand() % 26]);
}
I'm implementing a dynamic array; the main issue is that when I call the insertBack() function control will never reach inside because the condition is met i.e. since Capacity is 0 and n (which is the size) is also 0; it can never go inside the code block. How would I go about fixing this issue? I tried making an overloaded constructor and passing a certain Capacity--it didn't work out.
#include <iostream>
template<typename T>
class container
{
template <typename T2>
friend std::ostream& operator<<(std::ostream& out, const container<T2> &cobj);
public:
container();
~container();
bool isEmpty() const;
bool isFull();
int size() const;
int capacity() const;
bool insertBack(const T& val);
private:
void allocate(T* &temp);
T *arr;
int Capacity;
int n;
};
template<typename T2>
std::ostream& operator<<(std::ostream& out, const container<T2> &cobj)
{
std::cout << "Currently it contains " << cobj.size() << " value(s)" << std::endl
<< "Container storage capacity = " << cobj.capacity() << std::endl
<< "The contents of the container:" << std::endl;
if (cobj.isEmpty())
{
std::cout << "*** Container is currently empty!" << std::endl;
}
else
{
for (int i=0; i<cobj.size(); ++i)
{
std::cout << cobj.arr[i] << " ";
}
}
return out;
}
template<typename T>
container<T>::container()
{
arr = new T[Capacity];
n = 0;
}
template<typename T>
container<T>::~container()
{
delete []arr;
arr = nullptr;
std::cout << "Destructor called! (this line is normally not displayed)" << std::endl;
}
template<typename T>
bool container<T>::isEmpty() const
{
return n==0;
}
template<typename T>
bool container<T>::isFull()
{
return n==Capacity;
}
template<typename T>
int container<T>::capacity() const
{
return Capacity;
}
template<typename T>
int container<T>::size() const
{
return n;
}
template<typename T>
bool container<T>::insertBack(const T& val)
{
if (!isFull())
{
T* old_array = arr;
for (int i=0; i<n; ++i)
{
arr[i] = old_array[i];
}
arr[n] = val;
n++;
delete[] old_array;
return true;
}
else
{
allocate(arr);
return false;
}
}
template<typename T>
void container<T>::allocate(T* &temp)
{
if (Capacity==0)
{
temp = new T;
}
else
{
temp = new T[Capacity <<= 1];
}
}
int main()
{
container<int> a1;
std::cout << a1 << std::endl;
std::cout << "Currently, the container object contains 0 element(s) or 0 value(s)" << std::endl;
std::cout << "\nWe now insert 5 values at the back of the array, one at a time:" << std::endl;
const int num = 5;
for (int i=1, c=10; i<=num; ++i, c+=10)
{
a1.insertBack(c);
std::cout << a1 << std::endl << std::endl;
}
}
In the code shown below, in the function void printExpensiveThanT(..) i'm supposed to print out the destination, distance and the price for the offers which are more expensive than the offer T in the function, sorted in ascending order by the distance value.
I'm not sure what should i use to sort them, i experimented something with vectors but it didn't work out so i deleted it.
Any help would be appreciated.
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
class Transport {
protected:
char destination[100];
int basePrice;
int distance;
public:
Transport() {}
Transport(char *destination, int basePrice, int distance) {
strcpy(this->destination, destination);
this->basePrice = basePrice;
this->distance = distance;
}
virtual ~Transport() {}
virtual int priceTransport() = 0;
friend bool operator<(const Transport &t1, const Transport &t2) {
return t1.distance<t2.distance;
}
int getDistance(){ return distance; }
char *getDestination() { return destination; }
int getPrice() { return basePrice; }
};
class AutomobileTransport : public Transport {
private:
bool ifDriver;
public:
AutomobileTransport() {}
AutomobileTransport(char *destination, int basePrice,int distance, bool ifDriver) : Transport(destination,basePrice,distance) {
this->ifDriver = ifDriver;
}
void setIfDriver(bool ifDriver) {
this->ifDriver = ifDriver;
}
bool getIfDriver() {
return ifDriver;
}
int priceTransport() {
if(ifDriver) {
basePrice+=basePrice*20/100;
}
return basePrice;
}
friend bool operator<(const AutomobileTransport &a1, const AutomobileTransport &a2) {
return a1.distance<a2.distance;
}
};
class VanTransport: public Transport {
private:
int passengers;
public:
VanTransport() {}
VanTransport(char *destination, int basePrice, int distance, int passengers) : Transport(destination, basePrice, distance) {
this->passengers = passengers;
}
void setPassengers(int passengers) {
this->passengers = passengers;
}
int getPassengers() {
return passengers;
}
int priceTransport() {
for(int i = 0; i < passengers; i++) {
basePrice-=200;
}
return basePrice;
}
friend bool operator<(const VanTransport &k1, const VanTransport &k2) {
return k1.distance<k2.distance;
}
};
void printExpensiveThanT(Transport **offers,int n,AutomobileTransport &T) {
Transport *tmp;
for(int i = 0; i <= n; i++){
if(offers[i]->priceTransport() > T.priceTransport())
cout<<offers[i]->getDestination()<<" "<<offers[i]->getDistance()<<" "<<offers[i]->getPrice()<<endl;
}
}
int main() {
char destination[20];
int type,price,distance,passengers;
bool driver;
int n;
cin>>n;
Transport **offers;
offers=new Transport *[n];
for (int i=0; i<n; i++) {
cin>>type>>destination>>price>>distance;
if (type==1) {
cin>>driver;
offers[i]=new AutomobileTransport(destination,price,distance,driver);
} else {
cin>>passengers;
offers[i]=new VanTransport(destination,price,distance,passengers);
}
}
AutomobileTransport at("Ohrid",2000,600,false);
printExpensiveThanT(offers,n,at);
for (int i=0; i<n; i++) delete offers[i];
delete [] offers;
return 0;
}
Since you're dealing with pointers, the easiest thing to do is to use std::vector and std::sort:
#include <vector>
//...
void printExpensiveThanT(Transport **offers, int n, AutomobileTransport &T)
{
std::vector<Transport*> sortedVect;
for (int i = 0; i < n; i++)
{
if (offers[i]->priceTransport() > T.priceTransport())
sortedVect.push_back(offers[i]); // add this item to the vector
}
// sort the vector based on the dereferenced pointers and their respective
// operator <
std::sort(sortedVect.begin(), sortedVect.end(),
[](Transport* left, Transport* right) { return *left < *right; });
// print out the values
for (auto it : sortedVect)
cout << (*it).getDestination() << " " << (*it).getDistance() << " " << (*it).getPrice() << "\n";
}
Also, your original code looped one more than it should (i <= n was wrong).
Edit:
If your compiler doesn't support the C++ 11 syntax, here is an alternate solution:
#include <vector>
//...
bool Sorter(Transport* left, Transport* right)
{ return *left < *right; }
void printExpensiveThanT(Transport **offers, int n, AutomobileTransport &T)
{
std::vector<Transport*> sortedVect;
for (int i = 0; i < n; i++)
{
if (offers[i]->priceTransport() > T.priceTransport())
sortedVect.push_back(offers[i]); // add this item to the vector
}
// sort the vector based on the dereferenced pointers and their respective
// operator <
std::sort(sortedVect.begin(), sortedVect.end(), Sorter);
// print out the values
std::vector<Transport*>::iterator it = sortedVect.begin();
while (it != sortedVect.end())
{
cout << (*it).getDestination() << " " << (*it).getDistance() << " " << (*it).getPrice() << "\n";
++it;
}
}
Okay this program is to let some user enter an amount of numbers and it will output them in a straight line with commas in between. I have got every other code to work except for overloading the output operator.
Here's the header file:
#ifndef LISTTYPE_H_INCLUDED
#define LISTTYPE_H_INCLUDED
#include <iostream>
class ListType {
public:
ListType(size_t=10);
virtual ~ListType();
virtual bool insert(int)=0;
virtual bool erase();
virtual bool erase(int)=0;
virtual bool find(int) const=0;
size_t size() const;
bool empty() const;
bool full() const;
friend std::ostream& operator << (std::ostream&, const ListType&);
protected:
int *items;
size_t capacity;
size_t count;
};
Here's the cpp file:
#include "ListType.h"
ListType::ListType (size_t a) {
capacity = a;
count = 0;
items = new int [capacity];
}
ListType::~ListType() {
delete [] items;
}
bool ListType::erase() {
count = 0;
return 0;
}
size_t ListType::size() const {
return (count);
}
bool ListType::empty() const {
return (count == 0);
}
bool ListType::full() const {
return (count == capacity);
}
std::ostream& operator << (std::ostream& out, const ListType& list1) {
int a = 0;
out << list1[a] << ", " ;
return out;
}
Any help will be deeply appreciated.
You can use a function similar to this in your class:
void ListType::output(std::ostream& out) const {
for (int i = 0; i < count; i++) {
if (i > 0) { // No comma for first element
out << ", ";
}
out << items[i];
}
}
The overloaded << method of ostream can then be rewritten to this to call the output function:
std::ostream& operator << (std::ostream& out, const ListType& my_list) {
my_list.output(out);
return out;
}