I want to write a print function for a class AutoData that has information about cars in it. With this print function, I would ideally like to print out a vector that contains many different class objects. I have already written get functions for each element of the objects, but I am still a bit unsure of how to go about using those to write a function to print out the data in the following format:
mpg:cylinders:displacement:horsepower:weight:acceleration:modelYear:origin:carName
For example:
10.0:8:360.0:215.0:4615.:14.0:70:1:ford f250
10.0:8:307.0:200.0:4376.:15.0:70:1:chevy c20
11.0:8:318.0:210.0:4382.:13.5:70:1:dodge d200
The class is:
#include <string>
#include <vector>
#include <iostream>
using namespace std;
class AutoData {
public:
AutoData()
{
mpg = 0;
cylinders = 0;
displacement = 0;
horsepower = 0;
weight = 0;
acceleration = 0;
modelYear = 0;
origin = 0;
carName = "";
}
AutoData( const AutoData & rhs)
{
setAuto(rhs.mpg, rhs.cylinders, rhs.displacement, rhs.horsepower, rhs.weight, rhs.acceleration, rhs.modelYear, rhs.origin, rhs.carName);
}
void setAuto(float mp, int cy, float di, float ho, float we, float ac, int mo, int o, string ca)
{
mpg = mp;
cylinders = cy;
displacement = di;
horsepower = ho;
weight = we;
acceleration = ac;
modelYear = mo;
origin = o;
carName = ca;
}
const float & getmpg( ) const
{
return mpg;
}
const int & getcylinders( ) const
{
return cylinders;
}
const float & getdisplacement( ) const
{
return displacement;
}
const float & gethorsepower( ) const
{
return horsepower;
}
const float & getweight( ) const
{
return weight;
}
const float & getacceleration( ) const
{
return acceleration;
}
const int & getmodelYear( ) const
{
return modelYear;
}
const int & getorigin( ) const
{
return origin;
}
const string & getcarName( ) const
{
return carName;
}
bool operator == (const AutoData & rhs ) const
{
if( getmpg( ) == rhs.getmpg( ) )
{
return gethorsepower( ) == rhs.gethorsepower( );
}
else
{
return false;
}
}
bool operator > ( const AutoData & rhs ) const
{
if( rhs.getmpg( ) > getmpg( ) )
{
return true;
}
else if( getmpg( ) == rhs.getmpg( ) )
{
if( rhs.gethorsepower( ) > gethorsepower( ) )
{
return true;
}
}
else
{
return false;
}
}
private:
float mpg;
int cylinders;
float displacement;
float horsepower;
float weight;
float acceleration;
int modelYear;
int origin;
string carName;
};
Any help/advice anyone can provide would be very much appreciated!! Thanks
If you want to be able to do std::cout << AutoData();, you need to overload the output stream operator operator<<:
std::ostream& operator<< (std::ostream &out, AutoData const& data) {
out << data.getmpg() << ':';
out << data.getcylinders() << ':';
// and so on...
return out;
}
This function is not a member function, and since you have getters for each attribute, you do not have to declare this function as friend of your class.
Then you can do:
AutoData myAuto;
std::cout << myAuto << '\n';
What have you tried so far? My approach would be overloading operator<<, like:
std::ostream& operator<<(std::ostream& out, const AutoData& dasAuto) {
return out << dasAuto.getmpg() << ':' << dasAuto.getcylinders() <<
/* insert everthing in the desired order here */
std::endl;
}
And the same thing for the "reading" function, like:
std::istream& operator>>(std::istream& in, AutoData& dasAuto) {
float mpg;
int cylinders;
float displacement;
float horsepower;
float weight;
float acceleration;
int modelYear;
int origin;
string carName;
char separator;
const char SEP = ':';
if( !(in >> mpg >> separator) || (separator != SEP) ) return in;
if( !(in >> cylinders >> separator) || (separator != SEP) ) return in;
/* rinse, repeat */
if( !std::getline(in, carName) ) return in;
dasAuto.setAuto(mpg, cylinders /*, etc etc */);
return in;
}
You can read this artical to know about friend and operator <<,
http://www.cprogramming.com/tutorial/friends.html
In the class AutoData, you should declare this function:
friend ostream& operator<< (ostream& out, const AutoData& obj);
outside the class, you should define this function like this:
ostream& operator<< (ostream& out, const AutoData& obj)
{
out<<obj.mpg<<":";
//do what you want
return out;
}
Related
I have done the algorithm the expected output is :
p00 - p01,
p01 - p03 ,
p03 - p10,
p10 - p12 ,
p12 - p00
But I get this instead:
Convex hull:
p00 - p01
p01 - p03
p03 - p05
p05 - p10
p10 - p00
Points:
p00: (-5,-6)
p01: (6,-4)
p02: (5.5,-3)
p03: (8,0)
p04: (5,0)
p05: (4,2)
p06: (1,3)
p07: (0,2)
p08: (-1,1)
p09: (-1.5,2)
p10: (-1.5,6)
p11: (-5.5,1.5)
p12: (-8,-1)
I have been trying so long to get it right but some how I can't. Can anyone help? I am using C++
Below is my code:
I have 3 classes Vector2D, Point2D and Point2DSet my Graham Scan Implementation is in the buildConvexHull function in the Point2DSet.
Vector2D.cpp
#include "Vector2D.h"
Vector2D::Vector2D(double aX, double aY): fX(aX), fY(aY){ }
void Vector2D::setX(double aX){ fX = aX;}
double Vector2D::getX() const { return fX; }
void Vector2D::setY(double aY) { fY = aY;}
double Vector2D::getY() const { return fY; }
Vector2D Vector2D::operator+(const Vector2D& aRHS) const
{
return (fX + aRHS.fX, fY + aRHS.fY);
}
Vector2D Vector2D::operator-(const Vector2D& aRHS) const
{
return (fX - aRHS.fX, fY - aRHS.fY);
}
double Vector2D::magnitude() const
{
return sqrt((fX * fX) + (fY * fY));
}
double Vector2D::direction() const
{
return atan(fY/fX);
}
double Vector2D::dot(const Vector2D& aRHS) const
{
return (this->getX() * aRHS.getX()) + (this->getY() * aRHS.getY());
}
double Vector2D::cross(const Vector2D& aRHS) const
{
return (this->getX() * aRHS.getY()) - (aRHS.getX() * this->getY());
}
double Vector2D::angleBetween(const Vector2D& aRHS) const
{
double dntmr = magnitude() * aRHS.magnitude();
if (dntmr > 0.0)
{
return acos(this->dot(aRHS) / (this->magnitude() * aRHS.magnitude()));
}
return acos(1.0/1.0);
}
std::ostream& operator<<(std::ostream& aOutStream, const Vector2D& aObject)
{
aOutStream << " ( " << aObject.fX << ", " << aObject.fY << " )\n";
return aOutStream;
}
std::istream& operator>>(std::istream& aInStream, Vector2D& aObject)
{
aInStream >> aObject.fX;
aInStream >> aObject.fY;
return aInStream;
}
Point2D
#include "Point2D.h"
static const Point2D gCoordinateOrigin;
// Private function gets direction in reference to aOther
double Point2D::directionTo(const Point2D& aOther) const
{
return (aOther.fPosition - fPosition).direction();
}
// Private Function to get magnitude in reference to aOther
double Point2D::magnitudeTo(const Point2D& aOther) const
{
return (aOther.fPosition - fPosition).magnitude();
}
Point2D::Point2D() : fId(" "), fPosition(0,0), fOrigin(&gCoordinateOrigin) { }
Point2D::Point2D(const std::string& aId, double aX, double aY) : fId(aId), fPosition(aX,aY), fOrigin(&gCoordinateOrigin) { }
Point2D::Point2D(std::istream &aIStream) : fOrigin(&gCoordinateOrigin)
{
aIStream >> fId >> fPosition;
}
const std::string& Point2D::getId() const { return fId; }
void Point2D::setX(const double& aX) { fPosition.setX(aX); }
void Point2D::setY(const double& aY) { fPosition.setY(aY); }
const double Point2D::getX() const { return fPosition.getX(); }
const double Point2D::getY() const { return fPosition.getY(); }
void Point2D::setOrigin(const Point2D& aPoint) { fOrigin = &aPoint;}
Vector2D Point2D::operator-(const Point2D& aRHS) const
{
return (fPosition - aRHS.fPosition);
}
// Return Direction with reference to origin
double Point2D::direction() const
{
return fOrigin->directionTo(*this);
}
// Return Direction with reference to origin
double Point2D::magnitude() const
{
return fOrigin->magnitudeTo(*this);;
}
bool Point2D::isCollinear(const Point2D& aOther) const
{
if (fPosition.cross(aOther.fPosition) == 0)
{
return true;
}
return false;
}
// Check to see if the point is Clockwise or not
bool Point2D::isClockwise(const Point2D& aP0, const Point2D& aP2) const
{
double val = (fPosition.getY() - aP0.fPosition.getY()) * (aP2.fPosition.getX() - fPosition.getX()) -
(fPosition.getX() - aP0.fPosition.getX()) * (aP2.fPosition.getY() - fPosition.getY());
double val2 = fPosition.angleBetween(aP2.fPosition) - fPosition.angleBetween(aP0.fPosition);
if (val < 0 )
{
return false;
}
return true;
}
bool Point2D::operator<(const Point2D& aRHS) const
{
if (fPosition.getY() < aRHS.getY())
{
return true;
}
return false;
}
const Point2D& Point2D::getOrigin() const { return *fOrigin;}
std::ostream& operator<<(std::ostream& aOStream, const Point2D& aObject)
{
aOStream << aObject.fId << " : " << aObject.fPosition;
return aOStream;
}
std::istream& operator>>(std::istream& aIStream, Point2D& aObject)
{
aIStream >> aObject.fId >> aObject.fPosition;
return aIStream;
}
Point2DSet
#include "Point2DSet.h"
#include <fstream>
#include <stdexcept>
#include <algorithm>
void Point2DSet::add(const Point2D& aPoint)
{
fPoints.push_back(aPoint);
}
void Point2DSet::add(Point2D&& aPoint)
{
fPoints.push_back(aPoint);
}
void Point2DSet::removeLast()
{
fPoints.pop_back();
}
bool Point2DSet::doesNotTurnLeft(const Point2D& aPoint) const
{
return fPoints[size()-1].isClockwise(fPoints[size()-2],aPoint);
}
// Comparator function for Stable_sort
bool orderByCoordinates(const Point2D& aLeft, const Point2D& aRight)
{
return aLeft < aRight;
}
//Comparator function for Stable_sort
bool orderByPolarAngle(const Point2D& aLHS, const Point2D& aRHS)
{
if (aLHS.isCollinear(aRHS))
{
return aLHS.magnitude() > aRHS.magnitude();
}
return aLHS.direction() < aRHS.direction();
}
void Point2DSet::populate(const std::string& aFileName)
{
std::ifstream INPUT(aFileName);
//std::ifstream INPUT("Pointers.txt");
std::string id;
double x;
double y;
while (INPUT >> id >> x >> y)
{
Point2D z(id, x, y);
add(z);
}
INPUT.close();
}
void Point2DSet::buildConvexHull(Point2DSet& aConvexHull)
{
aConvexHull.clear();
sort(orderByCoordinates);
sort(orderByPolarAngle);
aConvexHull.add(fPoints[0]); // Origin (Smallest y-coordinate)
aConvexHull.add(fPoints[1]); //
//aConvexHull.add(fPoints[2]);
if (fPoints[2].isCollinear(fPoints[1])) {
aConvexHull.add(fPoints[2]);
}
//*/
for(size_t i = 3; i < size(); i++)
{
if (fPoints[i - 1].isCollinear(fPoints[i]))
{
continue; //i++;
}
if(aConvexHull.doesNotTurnLeft(fPoints[i]))
{
aConvexHull.removeLast();
}
aConvexHull.add(fPoints[i]);
}//*/
}
size_t Point2DSet::size() const
{
return fPoints.size();
}
void Point2DSet::clear()
{
fPoints.clear();
}
void Point2DSet::sort(Comparator aComparator)
{
stable_sort(fPoints.begin(), fPoints.end(), aComparator);
}
const Point2D& Point2DSet::operator[](size_t aIndex) const
{
return fPoints[aIndex];
}
Point2DSet::Iterator Point2DSet::begin() const
{
return fPoints.begin();
}
Point2DSet::Iterator Point2DSet::end() const
{
return fPoints.end();
}
Any other improvements are warmly welcome. Thank You!
There was a few issues in your code.
Let's start with Vector2D::direction(), you should use atan2, here the explanation why. After that we will be able to correctly sort the points.
Now the main algorithm. After a few changes it looks:
aConvexHull.clear();
// Get points with bigger magnitude first.
sort(orderByMagnitudeDescending);
sort(orderByPolarAngle);
// We want to have the lowest point as the first element.
rotatePointsByLowest();
aConvexHull.add(fPoints[0]); // Origin (Smallest y-coordinate)
aConvexHull.add(fPoints[1]);
for(size_t i = 2; i < size(); i++)
{
if (fPoints[i - 1].isCollinear(fPoints[i]))
{
continue; //i++;
}
// There should be a loop instead of an if statement.
while (aConvexHull.fPoints.size() > 2 && aConvexHull.doesNotTurnLeft(fPoints[i]))
{
aConvexHull.removeLast();
}
aConvexHull.add(fPoints[i]);
}//*/
The algorithm requires to find the lowest point and then traverse the rest of points according to their angle. I added a helper function Point2DSet::rotatePointsByLowest:
void Point2DSet::rotatePointsByLowest() {
auto lowestPoint = fPoints.begin();
for (auto iterator = fPoints.begin() + 1;iterator != fPoints.end(); iterator++) {
if (iterator->fPosition.fY < lowestPoint->fPosition.fY) {
lowestPoint = iterator;
} else if ((iterator->fPosition.fY == lowestPoint->fPosition.fY) && (iterator->fPosition.fX < lowestPoint->fPosition.fX)) {
lowestPoint = iterator;
}
}
std::rotate(fPoints.begin(), lowestPoint, fPoints.end());
}
There are more improvements that should be applied but I wanted to keep the changes minimal to show the issues causing the incorrect result.
Link for testing your project: https://onlinegdb.com/_ZXmQF2vJ
I'm using visual studio.
I have 3 class.
It's ok when I try to print Rectangle ABCD, but when i push ABCD into Array [rectangle] A and try to print ABCD again, the "wntdll.pdb not loaded" appear and i continue, it's "triggers breakpoint error!!" at delete in ~Rectangle()
I know it's something up to the pointer in class Rectangle but can't firgure out.
`int main(){
Array<Rectangle>A;
Rectangle a;
cout << a; //It's oke
A.PushBack(a); // problem here
cout<<a;
}`
class Point
{
private:
float _x;
float _y;
public:
float GetX() { return _x; }
float GetY() { return _y; }
public:
Point();
Point(float, float);
Point(const Point&);
~Point() {};
public:
string ToString() const;
public:
friend istream& operator>>(istream&, Point*);
friend ostream& operator<<(ostream&, const Point&);
};
Point::Point() {
_x = 1;
_y = 1;
}
Point::Point(float x, float y) {
_x = x;
_y = y;
}
Point::Point(const Point& a) {
_x = a._x;
_y = a._y;
}
string Point::ToString() const{
stringstream out;
out << "( " << _x << "," << _y << " )";
return out.str();
}
istream& operator>>(istream& in, Point* a) {
cout << "Nhap x: ";
in >> a->_x;
cout << "Nhap y: ";
in >> a->_y;
return in;
}
ostream& operator<<(ostream& out, const Point& a)
{
out << a.ToString();
return out;
}
```
class Rectangle
{
private:
Point* _topleft;
Point* _botright;
public:
void Set_topleft(Point tl) { _topleft = &tl; }
Point Get_topleft() { return *_topleft; }
void Set_botright(Point br) { _botright = &br; }
Point Get_botright() { return *_botright; }
public:
Rectangle();
Rectangle(Point*, Point*);
~Rectangle();
public:
string ToString() const;
public:
friend istream& operator>>(istream&, Rectangle&);
friend ostream& operator<<(ostream&, const Rectangle&);
};
Rectangle::Rectangle()
{
_topleft = new Point(0, 2);
_botright = new Point(3, 0);
}
Rectangle::Rectangle(Point* a, Point* b)
{
_topleft = new Point(*a);
_botright = new Point(*b);
}
Rectangle::~Rectangle()
{
delete _topleft;
delete _botright;
}
string Rectangle::ToString() const
{
stringstream out;
out << "A" << *_topleft << "+" << "D" << *_botright;
return out.str();
}
istream& operator>>(istream& in, Rectangle& a)
{
std::cout << "A( x,y ): ";
in >> a._topleft;
std::cout << "D( x,y ): ";
in >> a._botright;
return in;
}
ostream& operator<<(ostream& out, const Rectangle& a)
{
out << a.ToString();
return out;
}
```
template<class T>
class Array
{
private:
T* _a;
int _len;
public:
Array();
~Array();
public:
int length() { return _len; }
void PushBack(T);
T GetAt(int);
};
template<class T>
Array<T>::Array() {
_a = new T[128];
_len = 0;
}
template<class T>
Array<T>::~Array() {
delete[] _a;
_len = 0;
}
template<class T>
void Array<T>::PushBack(T value) {
if (_len >= 128)
{
std::cout << "Array is over size, which is 128\n";
return;
}
_a[_len] = value;
_len++;
}
template<class T>
T Array<T>::GetAt(int pos) {
return _a[pos];
}
```
The problem in your code is that when you PushBack the Rectangle object a into the array, you create copy of this object. This means that you just copy pointers _topleft and _botright. So in this part of code, you have 2 objects with the same pointers, so you're trying to delete twice the same part of memory.
To fix this you need to define own copy constructor, which will create new pointers in the new object.
Remember also to define own move constructors or make it disable for your class.
Rectangle(const Rectangle &other)
{
if(other._topleft)
_topleft= new Point(*other._topleft);
else
_topleft = nullptr;
if(other._botright)
_botright= new Point(*other._botright);
else
_topleft = nullptr;
}
The next problem is because of definition of void Array<T>::PushBack(T value). Please change it to the void Array<T>::PushBack(const T& value).
Also, try Rectangle(Rectangle&& o) = delete;
I am working on my school project that has a base class and a derived class with some other classes.
Product.h
#ifndef AMA_PRODUCT_H
#define AMA_PRODUCT_H
#include <iostream>
#include <fstream>
namespace AMA
{
const int max_sku_length = 7;
const int max_unit_length = 10;
const int max_name_length = 75;
const double TRate = 0.13;
class Product
{
private:
char m_type;
char m_sku[max_sku_length +1];
char m_unit[max_unit_length + 1];
char* m_name;
int m_Cquantity;
int m_Nquantity;
double m_price;
bool m_status;
protected:
void sku(const char* setSku) { strncpy(m_sku, setSku, max_sku_length); }
const char* name() const { return m_name; }
bool taxed() const { return m_status; }
const char* sku() const { return m_sku;}
void name(const char*);
const char* unit() const;
double price() const;
void message(const char*);
bool isClear() const;
public:
double cost() const;
bool operator==(const char* src) { return strcmp(m_sku, src) == 0; }
bool isEmpty() const { return ((m_sku[0] == '\0') && (m_name == nullptr) && (m_price == 0) && (m_Cquantity == 0)); }
int qtyNeeded() const { return m_Nquantity; }
int quantity() const { return m_Cquantity; }
int operator+=(int src) { return m_Cquantity += src; }
Product();
Product(const char* sku, const char* name, const char* unit, int qty = 0,
bool taxed = true, double price = 0.0, int qtyNeeded = 0);
Product(const Product&);
Product& operator=(const Product&);
~Product();
virtual std::fstream& store(std::fstream& file, bool addNewLine = true)const = 0;
virtual std::fstream& load(std::fstream& file) = 0;
virtual std::ostream& write(std::ostream& os, bool linear)const = 0;
virtual std::istream& read(std::istream& is) = 0;
double total_cost() const;
void quantity(int);
bool operator>(const char*) const;
bool operator>(const Product&) const;
};
std::ostream& operator<<(std::ostream&, const Product&);
std::istream& operator>>(std::istream&, Product&);
double operator+=(double&, const Product&);
}
#endif
MyProduct.h
#ifndef AMA_MY_PRODUCT_H
#define AMA_MY_PRODUCT_H
#include <fstream>
#include "Product.h"
#include "ErrorState.h"
namespace AMA {
class MyProduct : public Product {
public:
MyProduct();
MyProduct(const char* sku, const char* name, const char* unit, int qty = 0,
bool isTaxed = true, double price = 0.0, int qtyNeeded = 0);
const char* sku() const;
const char* name() const;
const char* unit() const;
bool taxed() const;
double price() const;
double cost() const;
};
class Test {
MyProduct product; // Error
const char* filename;
public:
Test(const char* file);
Test(const char* file, const char* theSku, const char* theName);
std::fstream& store(std::fstream& file, bool addNewLine = true) const;
std::fstream& load(std::fstream& file);
std::ostream& write(std::ostream& os, bool linear) const;
std::istream& read(std::istream& is);
int operator+=(int value);
bool operator==(const char* sku) const;
friend std::ostream& operator<<(std::ostream& os, const Test& test);
friend double operator+=(double& d, const Test& test);
friend std::istream& operator>>(std::istream& is, Test& test);
};
}
#endif
MyProduct.cpp
#include <iomanip>
#include <fstream>
#include <cstring>
#include "MyProduct.h"
#ifdef TAB
#undef TAB
#endif
#define TAB '\t'
using namespace std;
namespace AMA {
MyProduct::MyProduct() : Product("", "", "") {}
MyProduct::MyProduct(const char* sku, const char* name, const char* unit, int qty,
bool isTaxed, double price, int qtyNeeded) :
Product(sku, name, unit, qty, isTaxed, price, qtyNeeded) {}
const char* MyProduct::sku() const { return Product::sku(); }
const char* MyProduct::name() const { return Product::name(); }
const char* MyProduct::unit() const { return Product::unit(); }
bool MyProduct::taxed() const { return Product::taxed(); }
double MyProduct::price() const { return Product::price(); }
double MyProduct::cost() const { return Product::cost(); }
Test::Test(const char* file) : filename(file) { }
Test::Test(const char* file, const char* theSku, const char* theName) :
product(theSku, theName, ""), filename(file) { }
std::fstream& Test::store(std::fstream& file, bool addNewLine) const {
if (!product.isEmpty()) {
file.open(filename, ios::out | ios::app);
file << product.sku() << TAB << product.name() << TAB << product.unit() << TAB <<
(product.taxed() ? 1 : 0) << TAB << product.price() << TAB << product.quantity() << TAB <<
product.qtyNeeded() << endl;
file.clear();
file.close();
}
return file;
}
std::fstream& Test::load(std::fstream& file) {
char sku_[max_sku_length + 1];
char name[max_name_length + 1];
char unit[max_unit_length + 1];
int quantity, qtyNeeded;
double price_;
char taxed_;
file.open(filename, ios::in);
file >> sku_;
file >> name;
file >> unit;
file >> taxed_;
file >> price_;
file >> quantity;
file >> qtyNeeded;
file.clear();
file.close();
product = MyProduct(sku_, name, unit, quantity, taxed_ != 0, price_, qtyNeeded); //ERROR
return file;
}
std::ostream& Test::write(std::ostream& os, bool linear) const {
return product.isEmpty() ? os : (os << product.sku() << ": " << product.name() << ", quantity: "
<< product.quantity() << ", quantity needed:" << product.qtyNeeded()
<< ", Cost: " << fixed << setprecision(2) << product.cost());
}
std::istream& Test::read(std::istream& is) {
char sku_[max_sku_length + 1];
char name[max_name_length + 1];
char unit[max_unit_length + 1];
int quantity, qtyNeeded;
double price_;
char taxed_;
cout << " Sku: ";
is >> sku_;
cout << " Name (no spaces): ";
is >> name;
cout << " Unit: ";
is >> unit;
cout << " Taxed? (y/n): ";
is >> taxed_;
cout << " Price: ";
is >> price_;
cout << " Quantity On hand: ";
is >> quantity;
cout << " Quantity Needed: ";
is >> qtyNeeded;
product = MyProduct(sku_, name, unit, quantity, taxed_ != 0, price_, qtyNeeded); //ERROR
return is;
}
int Test::operator+=(int value) {
product.quantity(product += value);
return product.quantity();
}
bool Test::operator==(const char* sku) const {
return !std::strcmp(product.sku(), sku);
}
std::ostream& operator<<(std::ostream& os, const Test& test) {
return test.product.write(os, true);
}
double operator+=(double& d, const Test& test) {
return d += test.product.total_cost();
}
std::istream& operator>>(std::istream& is, Test& test) {
return test.product.read(is);
}
}
I am getting errors that I don't really know how to fix
object of abstract class type "AMA::MyProduct" is not allowed
'AMA::MyProduct': cannot instantiate abstract class
a cast to abstract class "AMA::MyProduct" is not allowed
Can someone help me out please?
The errors are self explanatory.
AMA::MyProduct is an abstract class, and such it cannot be instantiated directly.
A class is abstract when it has at least 1 abstract method (virtual and = 0 keywords on it). An abstract method MUST be overridden in a derived class, and you MUST instantiate that derived class, not the abstract class.
AMA::MyProduct is abstract because it does not override the 4 abstract methods it inherits from AMA::Product:
virtual std::fstream& store(std::fstream& file, bool addNewLine = true)const = 0;
virtual std::fstream& load(std::fstream& file) = 0;
virtual std::ostream& write(std::ostream& os, bool linear)const = 0;
virtual std::istream& read(std::istream& is) = 0;
You implemented them in AMA::Test instead of in AMA::MyProduct.
The way the code works is that there is a base pure virtual class called "Module" with subclasses of "Living", "Manufacturing" and "PowerGen" which uses some of the virtual functions. In the main driver file, I am successfully able to read a list of modules from a file and store them in a vector of Module pointers. The problem comes when I want to use the virtual display function to display that vectors element's module details. I am faced with a segmentation fault. Any help would be much appreciated!
Class Module
{
public:
Module() = default;
explicit Module(const string& purpose, const string& id)
{
this->purpose = purpose;
this->id = id;
}
explicit Module(const string& purpose) { this->purpose = purpose; }
virtual ~Module() { }
virtual void setCrew( ) = 0;
virtual void display( ) const = 0;
void addCrew(const string& name)
{
crew_list.push_back(Crew(name));
++number_of_crew;
}
void setPowerReq(double power) { this->power = power; }
void setMaxCrew(int max_crew) { this->max_crew = max_crew; }
string getPurpose( ) { return purpose; }
string getId( ) { return id; }
int getNumberOfCrew( ) { return number_of_crew; }
int getMaxCrew( ) { return max_crew; }
double getPower( ) { return power; }
friend ostream& operator << ( ostream& os, const Module& m );
friend ofstream& operator << ( ofstream& os, const Module& m );
friend ifstream& operator >> ( ifstream& is, Module& m );
private:
string purpose = "unknown";
string id = "unknown";
int number_of_crew = 0;
int max_crew = 0;
double power = 0;
vector<Crew> crew_list;
};
class Living : public Module
{
public :
Living( ) = default;
explicit Living(const string& purpose);
Living(int meals, const string& id);
void setCrew( )
{
setMaxCrew( floor(meals / 3) );
setPowerReq( meals * 1.4 );
}
void display( ) const
{
cout << *this;
}
friend ofstream& operator << ( ofstream& os, const Living& l );
friend ifstream& operator >> ( ifstream& is, Living& l );
private :
int meals = 0;
static string type;
};
class Manufacturing : public Module
{
public:
Manufacturing( ) = default;
Manufacturing( const string& product, int quantity, const string& id );
explicit Manufacturing( const string& purpose );
void setCrew( )
{
setPowerReq( quantity * 6 );
setMaxCrew( maxCrew );
}
void display( ) const
{
cout << *this;
}
friend ofstream& operator << ( ofstream& os, const Manufacturing& m );
friend ifstream& operator >> ( ifstream& is, Manufacturing& m );
private:
static string type;
string product = "unknown";
static int maxCrew;
int quantity = 0;
};
class PowerGen : public Module
{
public:
PowerGen() = default;
PowerGen( int number_of_generators, const string& id );
explicit PowerGen( const string& purpose );
void setCrew( )
{
setMaxCrew(0);
setPowerReq( -(number_of_generators * 7) );
}
void display( ) const
{
cout << *this;
}
friend ofstream& operator << ( ofstream& os, const PowerGen& p );
friend ifstream& operator >> ( ifstream& is, PowerGen& p );
private:
static string type;
const int max_generators = 8;
int number_of_generators = 0;
};
Portion relevant from the main driver file which when called causes the segmenation fault:
if( cityVector.size() > 0 )
{
cout << "\nHere is the complete City" << endl;
for ( auto iter : cityVector )
{
iter->display( );
cout << endl << endl;
}
} else {
cout << "\nThere are no Modules in the City" << endl;
}
This is how I loaded the data from a file, where VMOD = vector:
void load( VMOD & cityVector )
{
string filename;
cout << "Please enter a filename >> ";
getline( cin, filename );
ifstream fin;
fin.open(filename);
if (!fin.fail())
{
while ( !fin.eof() )
{
string purpose;
getline( fin, purpose );
if ( purpose == "Living" )
{
Living object(purpose);
loadObject( cityVector, object, fin );
} else if ( purpose == "Manufacturing" )
{
Manufacturing object(purpose);
loadObject( cityVector, object, fin );
} else if ( purpose == "Power Generation" )
{
PowerGen object(purpose);
loadObject( cityVector, object, fin );
} else {
}
}
cout << "The city has " << cityVector.size() << " modules!" << endl;
} else {
cout << "File does not exist... " << endl;
}
fin.close();
}
template<typename T>
void loadObject( VMOD & cityVector, T object, ifstream& fin )
{
fin >> object;
Module* mptr;
mptr = &object;
cityVector.push_back(mptr);
}
With the file looking like this:
Living
L1
5
21
2
First Person
Fourth Person
15
Manufacturing
M1
10
12
4
Second Person
Third Person
Fifth Person
Sixth Person
C++ ness
2
Power Generation
P1
0
-14
0
2
You have a dangling pointer problem.
template<typename T>
void loadObject( VMOD & cityVector, T object, ifstream& fin )
{
// object is a function local object
// since it is passed by value.
fin >> object;
Module* mptr;
// This is a pointer to a local object.
// It is invalid when the function returns.
mptr = &object;
// Storing a pointer that will be a dangling pointer as soon
// the function returns.
cityVector.push_back(mptr);
}
You need to use dynamically allocated memory for the restored objects and save them in cityVector.
You'll need to make sure that memory is deallocated once you are done using it.
template<typename T>
void loadObject(VMOD& cityVector, ifstream& fin )
{
T* objectPtr = new T;
fin >> *objectPtr;
cityVector.push_back(objectPtr);
}
and call it using the following syntax:
loadObject<LivingObject>(cityVector, fin);
I've been pulling my hair out over a certain error that seems to be plaguing my program. I've attempted to search online for cases similar to mine but I can't seem to find a way to apply the other solutions to this problem. My issue is as follows: When I initially open the program it immediately stops responding and crashes. Debugging led me to find the error in question is "0xC0000005: Access violation writing location 0xCCCCCCCC". It seems to be tied to me assigning two attributes (sku_ and name_ ) as '\0'. If I change these values to anything else such as "" or even "\0" the program runs in visual studio, but will fail to compile elsewhere. Could someone help me understand where I am going wrong?
Product.h
#ifndef SICT_Product_H__
#define SICT_Product_H__
#include "general.h"
#include "Streamable.h"
#include <cstring>
namespace sict {
class Product : public Streamable {
char sku_ [MAX_SKU_LEN + 1];
char* name_;
double price_;
bool taxed_;
int quantity_;
int qtyNeeded_;
public:
//Constructors
Product();
Product(const char* sku, const char* name1, bool taxed = true, double price = 0, int qtyNeeded =0);
Product(Product& g);
~Product();
//Putter Functions
void sku(const char* sku) { strcpy(sku_,sku); };
void price(double price) {price_ = price;};
void name(const char* name);
void taxed(bool taxed) { taxed_ = taxed; };
void quantity(int quantity) { quantity_ = quantity; };
void qtyNeeded(int qtyNeeded) { qtyNeeded_ = qtyNeeded; };
//Getter functions
const char* sku() const { return sku_; };
double price() const { return price_; };
const char* name() const { return name_; };
bool taxed() const { return taxed_; };
int quantity() const { return quantity_; };
int qtyNeeded() const { return qtyNeeded_; };
double cost() const;
bool isEmpty() const;
Product& operator=(const Product& );
bool operator==(const char* );
int operator+=(int );
int operator-=(int );
};
double operator+=(double& , const Product& );
std::ostream& operator<<(std::ostream& os, const Product& );
std::istream& operator>>(std::istream& is, Product& );
}
#endif
Product.cpp
#include <iostream>
#include <cstring>
#include "Product.h"
namespace sict {
Product::Product() {
sku_[0] = '\0';
name_[0] = '\0';
price_ = 0;
quantity_ = 0;
qtyNeeded_ = 0;
}
Product::Product(const char* sku, const char* name1, bool taxed1, double price1, int qtyNeeded1) {
strncpy(sku_, sku, MAX_SKU_LEN);
name(name1);
quantity_ = 0;
taxed(taxed1);
price(price1);
qtyNeeded(qtyNeeded1);
}
double Product::cost() const {
if (taxed_ == true) {
return (price_ * TAX) + price_;
}
else
return price_;
}
bool Product::isEmpty() const{
if (sku_ == nullptr && name_ == nullptr && quantity_ == 0 && price_ == 0 && qtyNeeded_ == 0) {
return true;
}
else
return false;
}
Product::Product(Product& ex) {
sku(ex.sku_);
price(ex.price_);
name(ex.name_);
taxed(ex.taxed_);
quantity(ex.quantity_);
qtyNeeded(ex.qtyNeeded_);
}
Product& Product::operator=(const Product& g) {
sku(g.sku_);
price(g.price_);
name(g.name_);
taxed(g.taxed_);
quantity(g.quantity_);
qtyNeeded(g.qtyNeeded_);
return *this;
}
Product::~Product() {
delete [] name_;
}
void Product::name(const char* name) {
name_ = new char [strlen(name) + 1];
strcpy(name_, name);
}
bool Product::operator==(const char* right) {
if (sku_ == right) {
return true;
}
else
return false;
}
int Product::operator+=(int g) {
quantity_ = quantity_ + g;
return quantity_;
}
int Product::operator-=(int g) {
quantity_ = quantity_ - g;
return quantity_;
}
double operator+=(double& p, const Product& right) {
p = p + (right.cost() * right.quantity());
return p;
}
std::ostream& operator<<(std::ostream& os, const Product& g) {
return g.write(os, true);
}
std::istream& operator>>(std::istream& is, Product& g) {
return g.read(is);
}
}
The General.h file referenced in the header is just a list of constant values such as the "TAX" and "MAX_SKU_LEN" values.
The Streamable header contains pure virtual functions. I will list it here in case it is needed.
Streamable.h
#ifndef SICT__Streamable_H_
#define SICT__Streamable_H_
#include <iostream>
#include <fstream>
#include "Product.h"
namespace sict {
class Streamable {
public:
virtual std::fstream& store(std::fstream& file, bool addNewLine = true)const = 0;
virtual std::fstream& load(std::fstream& file) = 0;
virtual std::ostream& write(std::ostream& os, bool linear)const = 0;
virtual std::istream& read(std::istream& is) = 0;
};
}
#endif
Thank you very much in advance.
Product::Product() {
sku_[0] = '\0';
name_[0] = '\0'; // <---- writing via unitialized pointer
price_ = 0;
quantity_ = 0;
qtyNeeded_ = 0;
}
There's one possible source of your problems. You have defined a char pointer (a dynamic array or a C-string, that is) name_ in your class but you never allocate any memory for it in your constructor, before attempting to record a value via the pointer. Naturally, you get a write access violation.
Before assigning the value to char at index [0] you need to first allocate space for at least one element in your string, e.g. by doing name_ = new char [1]. Alternatively, you may choose to initialize the pointer itself to NULL (or nullptr) and use that to indicate that name_ has not yet been set.