C++ - Overriden method not called properly (memory violation) - c++

In my program I'm trying to create abstract class called "DMA", from which "BaseDMA" inherits from it. Then classes "LacksDMA" and "HasDMA" inherits from "BaseDMA".
Every class override method
readInfo() from "DMA". Here is the code:
dma.h
#ifndef DMA_H_
#define DMA_H_
#include <iostream>
class DMA
{
protected:
char * label;
public:
DMA(const char * l);
DMA & operator=(const DMA & anotherDMA);
virtual ~DMA();
virtual void readInfo() const = 0;
char * getLabel() const ;
};
class BaseDMA: public DMA
{
private:
int rating;
public:
BaseDMA(const char * l, int r = 0);
BaseDMA(const BaseDMA & anotherBaseDMA);
virtual ~BaseDMA();
BaseDMA & operator=(const BaseDMA & anotherBaseDMA);
void readInfo() const override;
};
class LacksDMA: public BaseDMA
{
private:
enum { COL_LEN = 40 };
char color[COL_LEN];
public:
LacksDMA(const char * c = "no color", const char * l = "no color", int r = 0);
LacksDMA(const LacksDMA & anotherLacksDMA);
LacksDMA & operator=(const LacksDMA & anotherLacksDMA);
void readInfo() const override;
};
class HasDMA: public BaseDMA
{
private:
char * style;
public:
HasDMA(const char * s = "lack", const char * l = "lack", int r = 0);
HasDMA(const HasDMA & anotherHasDMA);
~HasDMA();
HasDMA & operator=(const HasDMA & anotherHasDMA);
void readInfo() const override;
};
#endif DMA_H_
dma.cpp
#include <string.h>
DMA::DMA(const char * l)
{
this->label = new char[strlen(l)+1];
strcpy(this->label, l);
}
DMA & DMA::operator=(const DMA & anotherDMA)
{
if(this == &anotherDMA)
return * this;
delete [] this->label;
this->label = new char[strlen(anotherDMA.label)+1];
strcpy(this->label, anotherDMA.label);
return *this;
}
char * DMA::getLabel() const
{
return this->getLabel();
}
DMA::~DMA()
{
delete [] label;
}
BaseDMA::BaseDMA(const char * l, int r)
: DMA(l)
{
this->rating = r;
}
BaseDMA::BaseDMA( const BaseDMA & anotherBaseDMA)
: DMA(anotherBaseDMA.label)
{
this->rating = anotherBaseDMA.rating;
}
BaseDMA::~BaseDMA()
{
}
BaseDMA & BaseDMA::operator=(const BaseDMA & anotherBaseDMA)
{
if(this == &anotherBaseDMA)
return *this;
DMA::operator=(anotherBaseDMA);
this->rating = anotherBaseDMA.rating;
return *this;
}
void BaseDMA::readInfo() const
{
std::cout << "BaseDMA object:\n";
std::cout << "Label: " << this->getLabel() << std::endl;
std::cout << "Rating: " << this->rating << std::endl;
}
LacksDMA::LacksDMA(const char * c, const char * l, int r)
:BaseDMA(l,r)
{
strcpy(this->color, c);
}
LacksDMA::LacksDMA(const LacksDMA & anotherLacksDMA)
: BaseDMA(anotherLacksDMA)
{
strcpy(this->color, anotherLacksDMA.color);
}
LacksDMA & LacksDMA::operator=(const LacksDMA & anotherLacksDMA)
{
if(this == &anotherLacksDMA)
return *this;
DMA::operator=(anotherLacksDMA);
strcpy(this->color, anotherLacksDMA.color);
return * this;
}
void LacksDMA::readInfo() const
{
BaseDMA::readInfo();
std::cout << "LacksDMA object:\n";
std::cout << "Color: " << color << std::endl;
}
HasDMA::HasDMA(const char * s, const char * l, int r)
:BaseDMA(l, r)
{
this->style = new char[strlen(s)+1];
strcpy(this->style, s);
}
HasDMA::HasDMA(const HasDMA & anotherHasDMA)
:BaseDMA(anotherHasDMA)
{
this->style = new char[strlen(anotherHasDMA.style)+1];
strcpy(this->style, anotherHasDMA.style);
}
HasDMA::~HasDMA()
{
delete [] this->style;
}
HasDMA & HasDMA::operator=(const HasDMA & anotherHasDMA)
{
if(this == &anotherHasDMA)
return *this;
BaseDMA::operator=(anotherHasDMA);
delete [] this->style;
this->style = new char[strlen(anotherHasDMA.style)+1];
strcpy(this->style, anotherHasDMA.style);
return *this;
}
void HasDMA::readInfo() const
{
BaseDMA::readInfo();
std::cout << "HasDMA object:\n";
std::cout << "Style: " << this->style << std::endl;
}
main.cpp
#include "dma.h"
void menuPanel();
void printDMS(DMA ** dms, int count);
int main()
{
const int DMA_COUNT = 4;
DMA * dmas[DMA_COUNT];
for(int i = 0; i < DMA_COUNT; i++)
{
void menuPanel();
int choice;
do
{
(std::cin >> choice).ignore();
if(std::cin.bad())
std::cin.clear();
} while (choice < 1 || choice > 3);
std::cout << "Write label: ";
char label[40];
std::cin.getline(label, 40);
std::cout << "Write rating: ";
int rating;
(std::cin >> rating).ignore();
if(choice == 1)
{
dmas[i] = new BaseDMA(label,rating);
std::cout << std::endl;
}
else if(choice == 2)
{
std::cout << "Write color: ";
char color[40];
std::cin.getline(color,40);
dmas[i] = new LacksDMA(color, label, rating);
}
else // choice == 3
{
std::cout << "write style: ";
char style[40];
std::cin.getline(style,40);
dmas[i] = new HasDMA(style, label, rating);
}
}
for(int i = 0; i < DMA_COUNT; i++)
delete dmas[i];
}
void menuPanel()
{
std::cout << "Panel action:\n";
std::cout << "1) make BbaseDMA" << std::endl;
std::cout << "2) make LacksDMA" << std::endl;
std::cout << "3) make HasDMA" << std::endl;
std::cout << std::endl;
}
void printDMS(DMA ** dms, int count)
{
for(int i = 0; i < count; i++)
{
dms[i]->readInfo();
std::cout << std::endl;
}
}
When I try to use runtime polymorphism with by calling readInfo() method in main() I get message about memory violation.
What I'm doing wrong?
Thank you in advance for your answers.

There are a number of issues with your code, but your memory issue is here:
char * DMA::getLabel() const
{
return this->getLabel();
}
As soon as getLabel() is called, such as in BaseDMA::readInfo(), you enter an endless recursion loop that eventually overflows the call stack.
DMA::getLabel() should be returning this->label instead:
char * DMA::getLabel() const
{
return this->label;
}

Related

Compilation error in C++ when using an assignment operator =?

I have written a program which was given to me as a homework assignment (it's a bit longer). The issue is that it compiles in CodeBlocks but it does not compile in Visual Studio 2017 it says - binary '=': no operator found which takes a right-hand operand of type 'CAutomobile' (or there is no acceptable conversion.
I would like to ask why is that because I could not myself find the error? I tried commenting the operator =function but still the error remained.
#include <iostream>
#include <algorithm>
#include <string>
#include <stdlib.h>
using namespace std;
class CVehicle {
string name;
int year;
public:
CVehicle() {
name = "Car";
year = 1990;
}
CVehicle(string n, int y) {
name = n;
year = y;
}
CVehicle(const CVehicle& vc) {
name = vc.name;
year = vc.year;
}
void setName(string n) {
name = n;
}
void setYear(int y) {
year = y;
}
string getName() {
return name;
}
int& getYear() {
return year;
}
virtual void Print(ostream& os) = 0;
};
class CAutomobile :public CVehicle {
double litres;
public:
CAutomobile() :CVehicle() {
litres = 7.2;
}
CAutomobile(string nm, int yr, double l) :CVehicle(nm, yr) {
litres = l;
}
void setLitres(double l) {
l = litres;
}
double& getLitres() {
return litres;
}
void Print(ostream& os) override {
os << getName() << endl;
os << getYear() << endl;
os << litres << endl;
}
friend bool operator< (CAutomobile a1, CAutomobile a2) {
if (a1.litres < a2.litres) {
return true;
}
return false;
}
CAutomobile operator= (CAutomobile& at) {
CAutomobile au;
au.getName() = at.getName();
au.getYear() = at.getYear();
au.getLitres() = at.getLitres();
return au;
}
CAutomobile operator+(CAutomobile aut) {
CAutomobile a;
a.getLitres() = getLitres() + aut.getLitres();
return a;
}
friend ostream& operator<< (ostream& o, CAutomobile a) {
o << a.getName() << endl;
o << a.getYear() << endl;
o << a.getLitres() << endl;
return o;
}
};
int main()
{
CAutomobile a[] = {
CAutomobile(),
CAutomobile("Wolkswagen",1970,80.5),
CAutomobile("Fiat",1979,21.9),
CAutomobile("Opel",1978,13.7)
};
for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++) {
cout << "Name" << ' ' << a[i].getName() << endl;
cout << "Year" << ' ' << a[i].getYear() << endl;
cout << "Litres" << ' ' << a[i].getLitres() << endl;
}
int range = 2016 - 1990 + 1;
for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++) {
a[i].setLitres(rand() % 100 + 1);
a[i].setYear(rand() % range + 1996);
}
//сортираме масива по литри и извеждаме
//най малкия (първия) му елемент
for (int i = 0; i < sizeof(a-1); i++) {
for (int j = 0; j < sizeof(a-1); j++) {
if (a[j].getLitres() > a[j + 1].getLitres()) {
swap(a[j], a[j + 1]);
}
}
}
cout << a[0] << endl;
CAutomobile k = a[0] + a[3];
cout << k.getLitres() << endl;
}
CAutomobile::operator = is completely wrong. It takes a non-const reference and assignes its field to a new object. Instead it should take a const reference and modify current object.
CAutomobile & operator =(CAutomobile const & other)
{
assert(this != ::std::addressof(other)); // check for self-assignment
SetName(other.getName());
SetYear(other.getYear());
SetLitres(other.getLitres());
return *this;
}
This will bring up another problem: getters are not const-qualified, so they should be fixes as well:
string const & getName(void) const {
return name;
}
int const & getYear(void) const {
return year;
}

Copy Constructor for dynamically allocated array

Trying to familiarize myself with the "Rule of 3" and Im having trouble getting a Copy Constructor to work. One of the class private members is returning 0 when it should have a value of 3.
Im not sure as to why when the Copy Constructor function is performed, a value of 0 is supplied to that classes private member. The member in question is theSize which is returned via the size() function in class.cpp.
class.h
class Catalog {
public:
Catalog (int maxCapacity = 100)
int size() const;
int capacity() const;
void add (Book b);
Catalog(const Catalog& c);
~Catalog();
Catalog& operator= (constCatalog& c) {
if (this != &c) {
delete[] books;
books = new Book[theCapacity];
*books = *(c.books);
}
return *this;
}
private:
Book* books;
int theCapacity;
int theSize;
};
class.cpp
Catalog::Catalog(int maxCapacity) {
theCapacity = maxCapacity;
theSize = 0;
books = new Book[theCapacity];
}
int Catalog::size() const {
return theSize();
}
int Catalog::capacity() const {
return theCapacity;
}
void Catalog::add (Book b)
{
if (theSize < theCapacity || contains(b.getID())) {
if (theSize == 0) {
books[0] = b;
theSize++;
}
else {
if (!contains(b.getID())) {
int i = theSize;
for (; i && b < books[i-1]; --i) {
books[i] = books[i - 1];
}
books[i] = b;
for (; i; --i) {
books[i - 1] = books[i - 1];
}
theSize++;
}
else {
for (int i = 0; i < theSize; ++i) {
if (b == books[i]) {
books[i] = b;
}
}
}
}
// Debugging only
/*for (int i = 0; i < theSize; i++) {
//cout << books[i] << endl;
}*/
}
}
bool Catalog::contains(std::string bookID) const
{
for (int i = 0; i < theSize; ++i)
{
if (books[i].getID() == bookID)
return true;
}
return false;
}
Catalog::Catalog(const Catalog& c) {
books = new Book[c.theSize];
for (int i = 0; i < c.theSize; i++) {
books[i] = c.books[i];
}
Catalog::~Catalog() {
delete[] books;
}
Later in main.cpp when I call c1.size() where c1 is the result of return c in another function that through use of the debugger comes from the Copy Constructor and then goes to the Destructor. However, c1.size() is returning as 0 though the Copy Constructor theSize = c.size() has a value of 3 when stepped through.
book.cpp
using namespace std;
/**
* Create a book.
*
* #param id the Gutenberg ID for this book
* #param authorInfo the author of the book
* #param title the title of the book
*/
Book::Book (std::string theId, std::string authorInfo, std::string theTitle)
: id(theId), authorName(authorInfo), title(theTitle)
{
}
bool Book::operator< (const Book& b) const
{
return id < b.id;
}
bool Book::operator== (const Book& b) const
{
return (id == b.id);
}
std::ostream& operator<< (std::ostream& out, const Book& b)
{
cout << b.getID() << "\t"
<< b.getAuthor() << "\t"
<< b.getTitle();
return out;
}
std::istream& operator>> (std::istream& in, Book& b)
{
string line;
getline (in, line);
if (!in.good())
return in;
int tab1 = line.find ("\t");
int tab2 = line.find ("\t", tab1+1);
string id = line.substr(0, tab1);
string author = line.substr (tab1+1, tab2-tab1-1);
string title = line.substr(tab2+1);
b.setID (id);
b.setAuthor (author);
b.setTitle (title);
return in;
}
main.cpp
using namespace std;
Catalog readCatalog(const string& fileName)
{
Catalog c;
ifstream in (fileName);
in >> c;
in.close();
return c;
}
Catalog mergeCatalogs (const Catalog& cat1, const Catalog& cat2)
{
Catalog result (cat1.size() + cat2.size());
int i = 0;
int j = 0;
while (i < cat1.size() && j < cat2.size())
{
Book b1 = cat1.get(i);
Book b2 = cat2.get(j);
if (b1.getID() < b2.getID())
{
result.add(b1);
++i;
}
else
{
result.add(b2);
++j;
}
}
while (i < cat1.size())
{
result.add(cat1.get(i));
++i;
}
while (j < cat2.size())
{
result.add(cat2.get(j));
++j;
}
return result;
}
void mergeCatalogFiles (const string& catalogFile1, const string& catalogFile2)
{
Catalog c1, c2;
c1 = readCatalog(catalogFile1);
cout << catalogFile1 << " contained " << c1.size() << " books." << endl;
c2 = readCatalog(catalogFile2);
cout << catalogFile2 << " contained " << c2.size() << " books." << endl;
Catalog c3 = mergeCatalogs (c1, c2);
cout << "Their merge contains " << c3.size() << " books." << endl;
cout << c3 << flush;
}
int main (int argc, char** argv)
{
if (argc != 3)
{
cerr << "Usage: " << argv[0] <<
"catalogFile1 catalogFile2" << endl;
return -1;
}
string file1 = argv[1];
string file2 = argv[2];
mergeCatalogFiles (file1, file2);
if (Counted::getCurrentCount() == 0)
{
cout << "No memory leak detected." << endl;
return 0;
}
else
{
cout << "Memory leak detected: " << Counted::getCurrentCount() << endl;
return -2;
}
}
Follow rule of zero: use std::vector<Book> to replace the array pointer and the size.
Your capacity is a limit on the size.
When at capacity. use equal range to find where to insert, replace last element then std rotate.
Managing both resources and business logic in the same class is bug prone. Do one thing at a time.
Try something more like this instead:
class Catalog
{
public:
Catalog (int maxCapacity = 100);
Catalog(const Catalog& c);
~Catalog();
int size() const;
int capacity() const;
void add (const Book &b);
Book* find(const std::string &bookID) const;
Catalog& operator= (Catalog c);
private:
Book* books;
int theCapacity;
int theSize;
void swap(Catalog &c);
};
#include "class.h"
#include <algorithm>
Catalog::Catalog(int maxCapacity)
{
theCapacity = maxCapacity;
theSize = 0;
books = new Book[theCapacity];
}
Catalog::Catalog(const Catalog& c)
{
theCapacity = c.theCapacity;
books = new Book[theCapacity];
for(int i = 0; i < c.theSize;; ++i)
books[i] = c.books[i];
theSize = c.theSize;
}
Catalog::~Catalog()
{
delete[] books;
}
Catalog& Catalog::operator= (const Catalog &c)
{
if (this != &c)
Catalog(c).swap(*this);
return *this;
}
void Catalog::swap(Catalog &c)
{
std::swap(books, c.books);
std::swap(theSize, c.theSize);
std::swap(theCapacity, c.theCapacity);
}
int Catalog::size() const
{
return theSize;
}
int Catalog::capacity() const
{
return theCapacity;
}
void Catalog::add (const Book &b)
{
Book *book = find(b.getID());
if (book) {
*book = b;
}
else if (theSize < theCapacity)
{
int i;
for (i = theSize; i && b < books[i-1]; --i) {
books[i] = books[i - 1];
}
books[i] = b;
++theSize;
}
// Debugging only
/*
for (int i = 0; i < theSize; ++i) {
cout << books[i] << endl;
}
*/
}
Book* Catalog::find(const std::string &bookID) const
{
for (int i = 0; i < theSize; ++i)
{
if (books[i].getID() == bookID)
return &books[i];
}
return 0;
}
That being said, this would be much simpler and easier to manage if you use std::vector and STL algorithms. Let the STL do the hard work for you:
#include <vector>
class Catalog
{
public:
Catalog (int initialCapacity = 100);
int size() const;
int capacity() const;
void add (const Book &b);
Book* find(const std::string &bookID) const;
private:
std::vector<Book> books;
};
#include "class.h"
#include <algorithm>
Catalog::Catalog(int initialCapacity)
{
books.reserve(initialCapacity);
}
int Catalog::size() const
{
return books.size();
}
int Catalog::capacity() const
{
return books.capacity();
}
void Catalog::add (const Book &b)
{
Book *book = find(b.getID());
if (book) {
*book = b;
}
else {
books.insert(std::upper_bound(books.begin(), books.end(), b), b);
}
// Debugging only
/*
for (Book &book: books) {
cout << book << endl;
}
*/
}
Book* Catalog::find(const std::string &bookID) const
{
auto iter = std::find_if(books.begin(), books.end(), [&bookID](const Book &b){ return (b.getID() == bookID); });
if (iter != books.end())
return &*iter;
return 0;
}

How to use std::sort to sort particular objects from an array?

I have those classes and I want to sort an array of objects, considering x coordinate, and sort just those with a particular value to an attribute.
Class.h
#include <iostream>
#include <algorithm>
class Punct2D
{
protected:
int x, y;
public:
Punct2D() {};
~Punct2D() {};
int get_x() const;
int get_y() const;
void set_x(const int x);
void set_y(const int y);
friend std::ostream &operator << (std::ostream &flux, Punct2D dot);
friend std::istream &operator >> (std::istream &flux, Punct2D &dot);
};
class Punct2DColorat :public Punct2D
{
private:
char *color;
public:
Punct2DColorat() { this->color = NULL; };
~Punct2DColorat() {};
char *get_color();
void set_color(char *color);
bool operator<(Punct2DColorat dot);
};
Here I have the implementation.
#include "Class.h"
int Punct2D::get_x() const
{
return this->x;
}
int Punct2D::get_y() const
{
return this->y;
}
void Punct2D::set_x(const int x)
{
this->x = x;
}
void Punct2D::set_y(const int y)
{
this->y = y;
}
char *Punct2DColorat::get_color()
{
return this->color;
}
void Punct2DColorat::set_color(char *color)
{
this->color = new char[strlen(color) + 1];
for (int i = 0; i < strlen(color) + 1; i++) this->color[i] = color[i];
}
bool Punct2DColorat::operator<(Punct2DColorat dot)
{
return this->x < dot.get_x();
}
std::ostream &operator << (std::ostream &flux, Punct2D dot)
{
flux << "Punct(" << dot.get_x() << "," << dot.get_y() << ")\n";
return flux;
}
std::istream &operator >> (std::istream &flux, Punct2D &dot)
{
std::cout << "Introduceti x :";
flux >> dot.x;
std::cout << "Introduceti y :";
flux >> dot.y;
return flux;
}
And here is the Main.
#include "Class.h"
void main()
{
int n, it = 0; char *aux = new char[15]; bool value;
Punct2DColorat *dots;
std::cout << "Cate puncte introduceti :"; std::cin >> n;
dots = new Punct2DColorat[n];
for (int i = 0; i < n; i++)
{
std::cout << "Introduceti 0 pentru Punct2D, respectiv 1 pentru Punct2D colorat :";
std::cin >> value;
if (value)
{
std::cin >> dots[i];
std::cout << "Introduceti culoarea punctului :";
std::cin >> aux;
dots[i].set_color(aux);
}
else
{
std::cin >> dots[i];
}
}
std::sort(dots, dots + n, [](Punct2DColorat dot) { return dot.get_color() != NULL; });
for (int i = 0; i < n; i++)
{
std::cout << dots[i];
if (dots[i].get_color() != NULL)
{
std::cout << "Culoare :" << dots[i].get_color() << "\n";
}
std::cout << "\n";
}
}
I want to sort the dots with color !=NULL, I tried this, it works but I have a runtime error.
bool Punct2DColorat::operator<(Punct2DColorat dot)
{
if ((this->color != NULL) && (dot.get_color() != NULL))return this->x < dot.get_x();
return true;
}
How can I sort just the objects with color !=NULL and the other objects with color==NULL remain in the same position?
Here is an example:
//If have 3 objects in the following order stored in the dots array.
dots[0].get_x()=3;
dots[0].get_y()=3;
dots[0].get_color()="Red";
dots[1].get_x()=0;
dots[1].get_y()=0;
dots[1].get_color()=NULL;
dots[2].get_x()=1;
dots[2].get_y()=1;
dots[2].get_color()="Blue";
//After sort i want to have them like this:
dots[0].get_x()=1;
dots[0].get_y()=1;
dots[0].get_color()="Blue";
dots[1].get_x()=0;
dots[1].get_y()=0;
dots[1].get_color()=NULL;
dots[2].get_x()=3;
dots[2].get_y()=3;
dots[2].get_color()="Red";
Thanks.
The problem is, your comparison operator evaluates to true for any couple of non-colored points.
A possible solution is to construct a second vector, sort it and re-insert
std::vector<Punct2DColorat> tmp;
for (int i = 0; i < n; i++)
{
if (dots[i].get_color() != NULL)
{
tmp.push_back(dots[i]);
}
}
std::sort(tmp.begin(), tmp.end());
int j = 0;
for (int i = 0; i < n; i++)
{
if (dots[i].get_color() != NULL)
{
dots[i] = tmp[j];
++j;
}
}

Creating a deck of Cards

Okay, first off I have looked at various of the questions that were asked about creating a deck of Cards but every single one I looked was using the vector thing, I'm not sure how to write it, cause I have not taken that subject in class so I don't know how to apply it.
The Card.H and Card.cpp are all fine, no need to change a thing in them
I need help in Deck.H and Deck.cpp.
My initialize() function is not finished and I cant seem to know how to finish it and with the other methods in the Deck class I have not tried to write any of them since I cant generate a deck of cards.
CARD.H
Class Card
{
int m_face;
char m_suit;
public:
Card(int _face = 2 , char _suit = 3);
~Card();
int GetFace() const;
char GetSuit() const;
void SetFace(int _face);
void SetSuit(char _suit);
void Show() const;
}
CARD.CPP
#include "Card.h"
Card::Card(int _face, char _suit)
{
m_face = _face;
m_suit = _suit;
}
Card::~Card()
{
}
int Card ::GetFace() const
{
return m_face;
}
char Card ::GetSuit() const
{
return m_suit;
}
void Card::SetFace(int _face)
{
m_face = _face;
}
void Card::SetSuit(char _suit)
{
m_suit = _suit;
}
void Card::Show() const
{
if (m_face == 11)
cout << " J " << m_suit << endl;
else if (m_face == 12)
cout << " Q " << m_suit << endl;
else if (m_face == 13)
cout << " K " << m_suit << endl;
else if (m_face == 14)
cout << " A " << m_suit << endl;
else
cout << m_face << m_suit << endl;
}
DECK.H
#pragma once
#include "stdafx.h"
#include "Card.h"
Class Deck
{
Card m_cards[52];
public:
Deck();
void Initialize();
void Shuffle();
bool Draw(Card& _card);
void Clear();
bool IsEmpty() const;
}
DECK.CPP
#include "Deck.h"
#include"Card.h"
void Deck::Initialize()
{
int count = 0;
char Suits[] = { 3, 4, 5, 6 };
for (int i = 0; i < 4; ++i) //Suits
{
for (int F = 2; F < 14; ++F) //faces
{
m_cards[count].SetSuit(Suits[i]);
m_cards[count].SetFace(F);
}
}
}
void Deck::Shuffle()
{
}
bool Deck::Draw(Card& _card
{
}
void Deck::Clear()
{
}
bool Deck::IsEmpty() const
{
}
I don't think your Initialize function needs much more work.
Only 2 remarks:
You forgot a ++count at the end of the inner for loop (now you're setting the same card every time).
As you wrote the inner for loop, the F variable will only be allowed to go up to 13 (because you used < 14). This means your deck won't contain any aces ... most logical thing for me would be to use <= 14 instead.
A little tweaking and it works.
#include <iostream>
#include <algorithm>
using namespace std;
class Card
{
private:
int m_face;
char m_suit;
public:
Card(int _face = 2 , char _suit = 3)
{
m_face = _face;
m_suit = _suit;
}
~Card(){}
int GetFace() const { return m_face; }
char GetSuit() const { return m_suit; }
void SetFace(int _face) { m_face = _face; }
void SetSuit(char _suit) { m_suit = _suit; }
void Show() const
{
if (m_face == 11)
cout << " J " << m_suit << endl;
else if (m_face == 12)
cout << " Q " << m_suit << endl;
else if (m_face == 13)
cout << " K " << m_suit << endl;
else if (m_face == 14)
cout << " A " << m_suit << endl;
else
cout << m_face << m_suit << endl;
}
};
class Deck
{
private:
Card m_cards[52];
int current;
public:
Deck() { Initialize(); }
void Initialize()
{
current = 51;
int count = 0;
char Suits[] = { 3, 4, 5, 6 };
for (int i = 0; i < 4; ++i) //Suits
{
for (int F = 2; F <= 14; ++F) //faces
{
m_cards[count++].SetSuit(Suits[i]);
m_cards[count++].SetFace(F);
}
}
}
void Shuffle() { std::random_shuffle(m_cards, m_cards + current + 1); }
bool Draw(Card& _card)
{
if (IsEmpty()) return false;
_card = m_cards[current--];
return true;
}
void Clear() { current = -1; }
bool IsEmpty() const { return current < 0; }
};
int main()
{
Deck deck;
while(!deck.IsEmpty())
{
Card c;
deck.Draw(c);
c.Show();
}
return 0;
}

Printing out information from a file by looping through another function designed to search the file - C++

I have this function that can scan my file and print out a predesignated record according to which one you choose to look at:
void addressBook::showRecord(int pickNum) {
PEOPLE2 p;
ifstream indata("vectortest.dat", ios::binary);
if(!indata) {
cout << "Error opening file for reading " << endl;
exit(0);
}
indata.seekg(pickNum * sizeof(PEOPLE2));
indata.read(reinterpret_cast <char*> (&p), sizeof(PEOPLE2));
cout << p.fName2 << " " << p.lName2 << " " << p.Address2 << " " << endl;
}
So all you have to do is pop showRecord into main, and then pick which name you want to print out. Say I want to look at the second name stored, I would put in
newBook->showRecord(1);
Thats all fine an dandy, and it works perfect, but what if I want to go a bit further. So I create another function that can use showRecord to print out all of the names in the address book that have been stored to my file. I tried this:
void addressBook::showAll() {
ifstream indata("vectortest.dat", ios::binary);
for(int i = 0; i < indata.end; i++) {
showRecord(i);
}
}
and it works, but it only prints out the stuff that's hard coded into my PERSON struct from a previous assignment:
addressBook *newBook = addressBook::newbookInst();
PERSON me[] = {{"First" , "Last", "ADDRESS"}, {"John", "Doe", "1234"}};
newBook->addPerson(me[1]);
newBook->addPerson(me[0]);
which is just odd beacuse when I go into the file itself, I can see all of the names that were added.
So how do I use this so that it actually prints out everything in the file, and not just the two entries that are permanently stored?
Here is my addressbook.h and addressbook.cpp code in case you need a better understanding of whats going on...
\\addressbook.h////////
#ifndef _ADDRESSBOOK
#define _ADDRESSBOOK
#include <fstream>
#include <vector>
#include<string>
using std::string;
#include <iostream>
using namespace std;
using std::istream;
using std::ostream;
namespace CJ
{
const int MAXADDRESS =25;
struct PERSON
{
string fName;
string lName;
string Address;
};
struct PEOPLE2
{
char fName2[25];
char lName2[25];
char Address2[25];
};
class addressBook
{
private:
vector<PERSON> people;
int head;
int tail;
public:
addressBook();
addressBook(const PERSON &p);
addressBook(const PERSON p[], int size);
addressBook(char *fName, char *lName, char *address);
bool addPerson(const PERSON &p);
bool sortcomp(const PERSON& p1, const PERSON& p2);
bool getPerson(PERSON &p);
bool findPerson(const string& lastName, PERSON& p);
bool findPerson(const string& lastName, const string& firstName, PERSON& p);
void bubbleSort(int *array,int length);
void printBook();
void sort();
void waitKey();
static addressBook *newbookInst();
static addressBook *tempNew;
static PERSON *p();
static PERSON *temPerson;
void showRecord(int pickNum);
void writeRecord();
void showAll();
friend ostream &operator << (ostream &, addressBook &);
addressBook operator =(const string& str);
addressBook &operator +=(const PERSON &p);
addressBook operator [](int x);
};
}
#endif
\\addressbook.cpp/////
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <conio.h>
#include <string>
using std::string;
#include "addressBook.h"
#include "menu.h"
namespace CJ
{
addressBook::addressBook()
: head(0), tail(-1)
{
}
addressBook::addressBook(const PERSON &p)
: head(0), tail(-1)
{
addPerson(p);
}
addressBook::addressBook(const PERSON p[], int size)
: head(0), tail(-1)
{
for(int i = 0; i < size; i++)
addPerson(p[i]);
}
addressBook::addressBook(char *fName, char *lName, char *Address)
: head(0), tail(-1)
{
PERSON tmp;
tmp.fName = fName;
tmp.lName = lName;
tmp.Address = Address;
addPerson(tmp);
}
bool addressBook::addPerson(const PERSON &p)
{
people.push_back(p);
if(tail == -1)
tail++;
return true;
}
bool addressBook::getPerson(PERSON &p)
{
if(tail >=0)
{
if(tail >= people.size())
tail = 0;
p = people[tail];
tail++;
return true;
}
return false;
}
bool addressBook::findPerson(const string &lastName, PERSON &p)
{
for(size_t i = 0; i < people.size(); i++)
{
if(people[i].lName == lastName)
{
PERSON *p = addressBook::p();
*p = people[i];
return true;
}
}
return false;
}
bool addressBook::findPerson(const string &lastName, const string &firstName, PERSON &p)
{
for(size_t i = 0; i < people.size(); i++)
{
if(people[i].lName == lastName && people[i].fName == firstName)
{
PERSON *p = addressBook::p();
*p = people[i];
return true;
}
}
return false;
}
void addressBook::printBook()
{
for(size_t i = 0; i < people.size(); i++)
{
std::cout << people[i].fName << "\t" << people[i].lName << "\t" << people[i].Address << std::endl;
}
}
bool addressBook::sortcomp(const PERSON& p1, const PERSON& p2)
{
int result = (p1.lName.compare(p2.lName)) ;
if ( result > 0 )
return true ;
if ( result < 0 )
return false ;
return (p1.fName.compare(p2.fName)) > 0 ;
}
void addressBook::sort()
{
bool didSwap ;
do
{
didSwap = false ;
for ( unsigned i=1; i<people.size(); ++i )
if ( sortcomp(people[i-1], people[i]) )
{
std::swap(people[i-1], people[i]) ;
didSwap = true ;
}
} while ( didSwap ) ;
}
addressBook &addressBook::operator +=(const PERSON &p)
{
addPerson(p);
return *this;
};
addressBook addressBook::operator [](int x)
{
return people[x];
};
ostream &operator << (ostream &output, addressBook &ab)
{
PERSON tmp;
ab.getPerson(tmp);
output << tmp.fName << " " << tmp.lName << " " << tmp.Address << endl;
return output;
}
addressBook * addressBook::tempNew = NULL;
addressBook *addressBook::newbookInst()
{
if(tempNew == NULL)
{
tempNew = new addressBook;
}
return tempNew;
}
PERSON * addressBook::temPerson = NULL;
PERSON *addressBook::p()
{
if(temPerson == NULL)
{
temPerson = new PERSON;
}
return temPerson;
}
bool status;
char lName[50];
char fName[50];
void addressBook::writeRecord()
{
PEOPLE2 temp;
ofstream outFile("vectortest.dat", ios::app);
if(!outFile)
{
cout << "Error opening file for writing " << endl;
return;
}
for (vector<PERSON>::iterator iter = people.begin(), end = people.end(); iter != end; ++iter)
{
strncpy(temp.fName2, iter->fName.c_str(), 25);
strncpy(temp.lName2, iter->lName.c_str(), 25);
strncpy(temp.Address2, iter->Address.c_str(), 25);
outFile.write(reinterpret_cast<const char *>(&temp), sizeof(PEOPLE2));
}
outFile.close();
}
void addressBook::showRecord(int pickNum)
{
PEOPLE2 p;
ifstream indata("vectortest.dat", ios::binary);
if(!indata)
{
cout << "Error opening file for reading " << endl;
exit(0);
}
indata.seekg(pickNum * sizeof(PEOPLE2));
indata.read(reinterpret_cast<char *>(&p), sizeof(PEOPLE2));
cout << p.fName2 << " " << p.lName2 << " " << p.Address2 << " " << endl;
indata.close();
}
void addressBook::showAll()
{
ifstream indata("vectortest.dat", ios::binary);
for(int i = 0; i < indata.end; i ++)
{
showRecord(i);
}
}
}
I don't really know that much about the context of how you're planning to use your address book class. But what I've done is re-work the basic structure of what you had into a little more idiomatic C++. This should hopefully help guide your future work on this class. The reading from file issue that you were having issues with is fixed.
#include <iostream>
#include <iterator>
#include <fstream>
#include <cstdlib>
#include <conio.h>
#include <string>
#include <vector>
#include <algorithm>
const int MAXADDRESS = 25;
struct PEOPLE2
{
char fName2[25];
char lName2[25];
char Address2[25];
};
struct PERSON
{
PERSON()
{}
PERSON(PEOPLE2 p)
: fName(p.fName2), lName(p.lName2), Address(p.Address2)
{}
PERSON(const std::string& first, const std::string& last, const std::string& add)
: fName(first), lName(last), Address(add)
{}
std::string fName;
std::string lName;
std::string Address;
};
// required for std::sort
bool operator< (const PERSON &lhs, const PERSON &rhs)
{
int result = (lhs.lName.compare(rhs.lName));
if(result == 0)
return lhs.fName < rhs.fName;
return result < 0;
}
// required for os << people
std::ostream& operator<< (std::ostream& os, const PERSON& rhs)
{
os << rhs.fName << " " << rhs.lName << " " << rhs.Address;
return os;
}
class addressBook
{
private:
std::vector<PERSON> people;
public:
addressBook()
{ }
addressBook(const PERSON &p)
{
addPerson(p);
}
template<typename IT>
addressBook(IT begin, IT end)
{
std::copy(begin, end, std::back_inserter(people));
}
addressBook(char *fName, char *lName, char *address)
{
PERSON tmp;
tmp.fName = fName;
tmp.lName = lName;
tmp.Address = address;
addPerson(tmp);
}
addressBook(const std::string& fileName)
{
std::ifstream indata(fileName, std::ios::binary);
PEOPLE2 p;
while(true)
{
indata.read(reinterpret_cast<char*>(&p), sizeof(PEOPLE2));
if(indata.fail())
break;
people.push_back(p);
}
}
void addPerson(const PERSON &p)
{
people.push_back(p);
}
bool findPerson(const std::string& lastName, PERSON& p)
{
std::find_if(std::begin(people), std::end(people), [&](const PERSON& in)->bool
{
if(lastName == in.lName)
{
p = in;
return true;
}
return false;
});
}
bool findPerson(const std::string& lastName, const std::string& firstName, PERSON& p)
{
std::find_if(std::begin(people), std::end(people), [&](const PERSON& in)->bool
{
if(lastName == in.lName && firstName == in.fName)
{
p = in;
return true;
}
return false;
});
}
void printBook()
{
std::for_each(std::begin(people), std::end(people), [](const PERSON& p)
{
std::cout << p.fName << "\t" << p.lName << "\t" << p.Address << std::endl;
});
}
void sort()
{
std::sort(std::begin(people),std::end(people));
}
void waitKey();
void showRecord(int pickNum)
{
std::cout << people[pickNum] << std::endl;
}
void writeRecord(const std::string& fileName)
{
PEOPLE2 temp;
std::ofstream outFile(fileName, std::ios::app);
if(!outFile)
{
std::cout << "Error opening file for writing " << std::endl;
return;
}
for(auto iter = people.begin(), end = people.end(); iter != end; ++iter)
{
strncpy(temp.fName2, iter->fName.c_str(), 25);
strncpy(temp.lName2, iter->lName.c_str(), 25);
strncpy(temp.Address2, iter->Address.c_str(), 25);
outFile.write(reinterpret_cast<const char *>(&temp), sizeof(PEOPLE2));
}
}
void showAll()
{
std::for_each(std::begin(people), std::end(people), [](const PERSON& in)
{
std::cout << in << std::endl;
});
}
friend std::ostream &operator << (std::ostream &output, addressBook &ab)
{
std::for_each(std::begin(ab.people), std::end(ab.people), [&](const PERSON& in)
{
output << in << "\n";
});
return output;
}
addressBook &operator +=(const PERSON &p)
{
addPerson(p);
return *this;
};
PERSON operator [](int x)
{
return people[x];
};
};
std::string fileName = "c:\\temp\\test.rec";
int main()
{
addressBook ab(fileName);
ab.sort();
ab.showAll();
//addressBook ab;
//ab.addPerson(PERSON("Mary", "Smith", "1 West Street"));
//ab.addPerson(PERSON("Joe", "Brown", "2 East Street"));
//ab.addPerson(PERSON("Harry", "Cooper", "3 South Street"));
//ab.writeRecord(fileName);
}