Access element of vector - c++

I have a class Student:
class Student {
private:
unsigned int id;
string name;
vector<int> grades;
public:
Student(unsigned int id, string name, vector<int> grades);;
virtual ~Student() {}
unsigned int getId() { return this->id; }
string getName() { return this->name; }
int getGradesAmount() { return this->grades.size(); }
vector<int> getGrades() { return this->grades; }
int getGrade(int i) { return this->grades[i]; }
unsigned int getCoef()
{
unsigned int coef = 1;
for (int i = 0; i < this->grades.size(); i++) { coef *= this->grades[i]; }
return coef;
}
int getNameCoef() { return this->getName().size() % 2; }
ostringstream getInfo()
{
ostringstream info;
info << "ID: " << getId() << ".\n";
info << "Name: " << getName() << ".\n";
info << "Amount of grades: " << getGradesAmount() << ".\n";
info << "Grades:";
for (int i = 0; i < getGradesAmount(); i++)
info << " " << getGrade(i);
info << "\nProduct of grades: " << getCoef() << ".\n";
info << "Is surname has odd number of symbols (0 = no / 1 = yes): " << getNameCoef() << ".\n";
return info;
}
};
Student::Student(unsigned int id, string name, vector<int> grades)
{
this->id = id; this->name = name; this->grades = grades;
}
And a class Group:
class Group : public Student {
protected:
int size = 0;
vector<Student> group;
public:
Group() : Student(getId(), getName(), getGrades()) {}
void addStudent(Student student)
{
if (student.getNameCoef() == 1)
{
if (this->group.size() > 0)
{
for (int i = 0; i < this->group.size(); i++)
{
if (student.getCoef() > group[i].getCoef())
{
this->group.insert(this->group.begin() + i, student);
this->size = this->size + 1;
return;
}
}
}
cout << "\nAdded to start";
this->group.push_back(student);
this->size = this->size + 1;
}
}
};
In Group I'm trying to overload << to make a cout << group.
So, I have added this into a Group:
friend ostream& operator<<(ostream& out, const Group& group) { // overloaded operator of output
out << "\nThere are " << group.size << " students in the group.\n";
for (int i = 0; i < group.size; i++)
{
out << "Student # " << i + 1 << ":\n";
out << group[i].getInfo();
}
return out;
}
But I have this error:
error C2676: binary '[': 'const Group' does not define this operator or a conversion to a type acceptable to the predefined operator
So, I googled for any [] overloaded operators for vector but didn't find anything that work for me. I also tried copying constructor, but it didn't helped me.
How to use group[i].getInfo() ? Or maybe there are some oter ways to access this. So, group[i] must be Student object.

It seems like you are confusing the group which is of type Group with its member, which is confusingly also called group.
Either you provide an Group::operator[] or you change your operator<< to
friend ostream& operator<<(ostream& out, const Group& group) { // overloaded operator of output
auto& vect = group.group;
out << "\nThere are " << vect.size() << " students in the group.\n";
for (int i = 0; i < vect.size(); i++)
{
out << "Student # " << i + 1 << ":\n";
out << vect[i].getInfo();
}
return out;
}

There are several issues with your code (see comments), but the one you're asking about is because of this line:
out << group[i].getInfo();
As JohnFileau mentioned, group is a Group object, not a std::vector. If you want to access the std::vector group in the Group class, you will need group.group:
out << group.group[i].getInfo();
This will fix this issue, but it's only fair to warn you you will soon hit others. I recommend reading the comments on your question and figuring out how to fix them.
Something worth noting here is that part of the reason you're seeing this is you may not realize that operator<<() is not a member function of Group. That is, even if you define it inline like this:
class Group : public Student {
//...
friend ostream& operator<<(ostream& out, const Group& group) { // overloaded operator of output
out << "\nThere are " << group.size << " students in the group.\n";
for (int i = 0; i < group.size; i++)
{
out << "Student # " << i + 1 << ":\n";
out << group[i].getInfo();
}
return out;
}
};
It might look like it's a member of Group, but it's actually not. It is an external friend function. It is not actually a part of Group. That means you can't access the data members directly. For instance,
this->size
will fail because, again, it's not actually a member function.
If you want to access data members of Group, you need to access them via the instance you were passed (i.e., group:
group.size
Note that that means when you do something like group.size, you're actually getting data member Group::size, not the size() from std::vector.

Related

`Vector.erase()` does not work for vector of classes

I've made a class of gym pass that has expiration date (int expiration), price for the pass (float price) and name of its' holder (string data). It also has services (char services), where 0 is basic, 1 is with free showers and 2 is VIP room.
Here's the definition of class:
class GymPass
{
int expiration; //the amount of days
char services; //0 - basic, 1 - shower, 2 - VIP room
float price = ((int)services - 47) * expiration;
string data; //client's identifiable data
public:
GymPass()
{
cout << "this: " << this;
expiration = 0;
services = '0';
price = 0;
data = "Lorem ipsum";
}
Pass(int expiration, char services, string data)
{
this->expiration = expiration;
this->services = services;
this->data = data;
}
void Print()
{
cout << "Gym Pass: ";
switch (services)
{
case '0':
{
cout << "Basic gym access, ";
}
case '1':
{
cout << "gym + shower room, ";
}
case '2':
{
cout << "Luxurious gym pass with VIP room, ";
}
default:
{
cout << "Error."; //this should never happen
}
}
cout << "valid for: " << expiration << " days, price: " << price << " zl." << endl;
}
void NewPass()
{
cout << "Choose service type: \n0 - basic\n1 - showers included\n2 - vip room included";
{
char temp{};
do
{
cin >> temp;
if (!((int)temp > 47 & (int)temp < 51)) cout << endl << "Incorrect service type.";
} while (!((int)temp > 47 & (int)temp < 51));
this->services = temp;
}
cout << endl << "Input the expiration date of the Pass:";
cin >> this->expiration;
cout << endl << "Input your name: ";
cin >> this->data;
}
friend bool operator==(const GymPass& lhs, const GymPass& rhs)
{
if (lhs.price != rhs.price) return false;
if (!(lhs.data._Equal(rhs.data))) return false;
if (lhs.services != rhs.services) return false;
if (lhs.expiration != rhs.expiration) return false;
return true;
}
};
I also made a class that's basically a vector of my GymPass classes. I'm trying to make a void function to delete one gym pass, but the erase throws error:
no instance of overloaded function "std::vector<_Ty, _Alloc>::erase [with _Ty=GymPass, _Alloc=std::allocator<GymPass>]" matches the argument list
Like a good programmer, I've done hours of googling, but to no luck. Here's definition of gym class
class Gym
{
vector <GymPass> Clients;
public:
void add(GymPass pass)
{
Clients.push_back(pass);
}
void remove(GymPass pass)
{
for (int i = 0; i < Clients.size(); i++)
{
if (Clients[i] == pass) Clients.erase(i);
}
}
};
void remove is the delete function, where I get the error. How do I fix the error?
std::vector::erase takes an iterator not an index as the argument.
Stali_Klienci.erase(Stali_Klienci.begin() + i);
is a reasonable hack. Stali_Klienci.begin() is the iterator to the first element, the + i increments the iterator to the ith element.
If you want to remove every element from a std::vector then clear does that in one call.
You must read erase() doc first: erase() expects an iterator
Then something like this must do the job:
for (auto it = Stali_Klienci.begin(); it != Stali_Klienci.end(); )
{
if (*it == karnet) {
it = c.erase(it);
} else {
++it;
}
}

Why is the 'info[]' of the struct records giving errors?

This program uses class and takes the info of employees from a file. I have mentioned the file below too. I have also mentioned the output i received even though there are error. There is something wrong in the output too but I think it is because of the info error that it's getting.
While running this program, I got this error message:
Error: Run-Time Check Failure #2 - Stack around the variable 'info' was corrupted.
There's also this message:
Unhandled exception at 0x00950A89 in employee.exe: Stack cookie instrumentation code detected a stack-based buffer overrun.
// The used file for this program is:
A.Smith 20001 25 40
T.Philip 20002 20 35
S.LOng 20003 15 50
G.Santos 20004 30 30
F.Farkas 20005 22 55
// The output after running even with the errors is:
This week's employee history
Name Id Rate Hours
* A.Smith 20001 $25/h 40h
* T.Philip 20002 $20/h 35h
* S.LOng 20003 $15/h 50h
* G.Santos 20004 $30/h 30h
* F.Farkas 20005 $22/h 55h
This week's payment
Name Payment
* ╠╠╠╠╠╠╠╠ $0 <----------There is this error too
* T.Philip $700
* S.LOng $825
* G.Santos $900
* A.Smith $1000
* The average wages of the employees: $685.00
// The code is:
/*
#include "pch.h"
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <string>
#include<iomanip>
*/
using namespace std;
struct records {
char name[50] = {};
char id[5] = {};
int rate = 0;
int hours = 0;
int pay = 0;
};
void take(records array[], const int a);
int calculator(records array[], const int a);
void swap(records array[], const int a);
double Average(records array[], int a);
ifstream infile;
int main()
{
const int n = 5;
This is the first time info is declared:
struct records info[n];
double averageWages;
int overTime = 0, i;
infile.open("Project 3.dat");
cout << "\n This week's employee history \n" << endl;
if (infile.is_open()) {
cout << " Name Id Rate Hours " << endl;
Here take function uses info of the struct:
take(info, n);
cout << endl << endl;
cout << "This week's payment\n" << endl;
cout << " Name Payment" << endl;
Also here other functions use info:
calculator(info, n);
swap(info, n);
for (i = 0; i < n; i++) {
cout << "*" << setw(10) << info[i].name << setw(10) << "$" << info[i].pay << endl;
}
averageWages = Average(info, n);
cout << "\n\n" << "* The average wages of the employees: $" << averageWages << endl << endl;
}
else {
cerr << "Error! file cannot open." << endl;
exit(1);
}
return 0;
}
// Taking records:
void take(records array[], const int a) {
for (int i = 0; i < a; i++) {
while (infile >> array[i].name >> array[i].id >> array[i].rate >> array[i].hours) {
cout << "*" << setw(9) << array[i].name << setw(10) << array[i].id << setw(10) << "$" << array[i].rate << "/h" << setw(10) << array[i].hours << "h " << endl;
}
} infile.close();
}
//swap records to arrange it according to total payment received
void swap(records array[], const int a) {
bool tf; //true or false
do {
tf = false;
for (int i = 0; i < a; i++) {
if (array[i].pay > array[i + 1].pay) {
swap(array[i], array[i + 1]);
tf = true;
}
}
} while (tf);
records temp;
for (int i = 0; i < a - 1; ++i)
{
for (int j = i + 1; j < a; ++j)
{
if (array[i].pay > array[j].pay)
{
temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
}
To calculate average:
double Average(records array[], const int a) {
double total = 0;
double average;
for (int i = 0; i < a; i++) {
total = total + (array[i].pay);
average = total / a;
}
cout.setf(ios::fixed);
cout.setf(ios::showpoint);
cout.precision(2);
return (total / a);
}
// To calculate the salary:
int calculator(records array[], const int a) {
infile.open("Project 3.dat");
if (infile.is_open()) {
for (int i = 0; i < a; i++) {
infile >> array[i].name >> array[i].id >> array[i].rate >> array[i].hours;
if (array[i].hours > 40) {
int overTime = (array[i].hours - 40)*1.5;
array[i].pay = ((array[i].rate) * 40) + (overTime*(array[i].rate));
}
else {
array[i].pay = (array[i].rate)*(array[i].hours);
}
}
for (int i = 0; i < a; i++) {
return (array[i].pay);
}
}
}
It's hard to find all potential problems with that fragmented code, but you'd be better off using std::strings instead of char[]. They are safer and also has a lot of built-in functions. They also work well with misc. functions in the STL.
Your struct records info[n]; will only hold n (5) elements. Use a standard container, like a std::vector instead in case you'd like to add more entries to the file.
Reading and writing to files can usually be done using custom stream operators and all the free functions you have to deal with a number of records could be collected in a class of its own. I've made one record struct and one Records class to demonstrate how they could be used Together.
#include <iostream>
#include <vector>
#include <iomanip>
#include <sstream>
#include <fstream>
#include <numeric>
#include <algorithm>
#include <functional>
struct record {
std::string name{};
std::string id{};
int rate = 0;
int hours = 0;
int pay = 0;
// stream operators for reading/writing a record
friend std::istream& operator>>(std::istream&, record&);
friend std::ofstream& operator<<(std::ofstream&, const record&);
friend std::ostream& operator<<(std::ostream&, const record&);
};
// populate a record from an istream
std::istream& operator>>(std::istream& is, record& r) {
std::string line;
// get a line and check that it's > 30 chars long
if(std::getline(is, line) && line.size()>30) {
// extract the name and remove trailing spaces
r.name = line.substr(0, 30);
auto pos = r.name.find_last_not_of(' ');
if(pos != std::string::npos)
r.name = r.name.substr(0, pos+1);
// put the rest of the line in a stringstream
std::stringstream ss(line.substr(30));
// and extract the rest of the fields
if(ss >> r.id >> r.rate >> r.hours) {
// calculate pay
r.pay = r.rate * r.hours;
} else { // if extraction fails, set the stream in fail mode
is.setstate(std::ios_base::failbit);
}
} else is.setstate(std::ios_base::failbit);
return is;
}
// streaming a record to an ofstream (like a file)
std::ofstream& operator<<(std::ofstream& os, const record& r) {
os << std::setw(30) << std::left << r.name.substr(0, 30) << r.id << " " << r.rate << " " << r.hours << "\n";
return os;
}
// streaming a record to a generic ostream (like std::cout)
std::ostream& operator<<(std::ostream& os, const record& r) {
os << "* " << std::setw(30) << std::left << r.name << std::right << r.id
<< " $" << r.rate << "/h " << r.hours << "h $" << std::setw(4) << r.pay;
return os;
}
class Records { // a class to maintain a number of "record"s
std::vector<record> m_records{}; // stores all "record"s
public:
Records(const std::string& filename) {
record tmp;
std::ifstream e(filename); // open file
// and extract one record at a time and put it in m_records.
while(e>>tmp) m_records.emplace_back(std::move(tmp));
}
// sum on any member in "record"
template <typename field>
auto Sum(field f) const {
return std::accumulate(m_records.begin(), m_records.end(), 0,
[&](int a, const record& b) { return a + (b.*f); });
}
// average of any member in "record"
template <typename field>
auto Average(field f) const {
return static_cast<double>(Sum(f)) / m_records.size();
}
// sorting on any member in "record"
template <typename field, typename T>
void Sort(field f, const T& cmp) {
std::sort(m_records.begin(), m_records.end(),
[&](const record& a, const record& b){ return cmp(a.*f, b.*f); });
}
// return the number of "record" elements
std::vector<record>::size_type size() const { return m_records.size(); }
// access an element via subscript
record& operator[](std::vector<record>::size_type idx) { return m_records[idx]; }
const record& operator[](std::vector<record>::size_type idx) const { return m_records[idx]; }
// iterators to use in for-loops
std::vector<record>::const_iterator cbegin() const noexcept { return m_records.cbegin(); }
std::vector<record>::const_iterator cend() const noexcept { return m_records.cend(); }
std::vector<record>::const_iterator begin() const noexcept { return cbegin(); }
std::vector<record>::const_iterator end() const noexcept { return cend(); }
std::vector<record>::iterator begin() noexcept { return m_records.begin(); }
std::vector<record>::iterator end() noexcept { return m_records.end(); }
// stream operator to show all records
friend std::ostream& operator<<(std::ostream&, const Records&);
};
std::ostream& operator<<(std::ostream& os, const Records& R) {
os << " Name Id Rate Hrs Pay\n";
for(const auto& r : R) std::cout << r << "\n";
os << std::setprecision(2) << std::fixed;
os << "Average pay : $" << std::setw(7) << R.Average(&record::pay) << "\n";
os << " rate : $" << std::setw(7) << R.Average(&record::rate) << "\n";
os << " hours worked: " << std::setw(7) << R.Average(&record::hours) << "h\n";
return os;
}
int main() {
// create a "Records" entity called "info" by reading a file
Records info("Project 3.dat");
// misc sorting and showing the result
std::cout << "Sorted as read from the file:\n";
std::cout << info;
std::cout << "\nSorted according to name:\n";
info.Sort(&record::name, std::less<std::string>());
std::cout << info;
std::cout << "\nSorted according to id:\n";
info.Sort(&record::id, std::less<std::string>());
std::cout << info;
std::cout << "\nSorted according to pay:\n";
info.Sort(&record::pay, std::greater<int>());
// output example using iterators:
for(auto& rec : info) {
std::cout << rec << "\n";
}
std::cout << "\nSorted according to rate:\n";
info.Sort(&record::rate, std::greater<int>());
std::cout << info;
std::cout << "\nSorted according to hours:\n";
info.Sort(&record::hours, std::greater<int>());
std::cout << info;
// example using subscript, operator[]
if(info.size()>2) {
std::cout << "\ninfo[2] = " << info[2] << "\n";
}
}

For Loop Method Call

An error pops up saying the class type does not provide a subscript operator.
I'm new to c++ and can't seem to figure this one out. Would be really thankful if you provided me some tips and where I'm going wrong in my code outside of the problem.
class Transaction {
protected:
char * ime;
char smetka[16];
float iznos;
Date d;
public:
Transaction() {}
Transaction( char * ime , char * smetka ,float iznos ,Date d ) {
this->ime = new char[strlen(ime)+1];
strcpy(this->ime,ime);
strcpy(this->smetka,smetka);
this->iznos=iznos;
this->d=d;
}
Transaction(const Transaction & c) {
ime = new char[strlen(ime)+1];
strcpy(this->ime,c.ime);
strcpy(this->smetka,c.smetka);
this->iznos=c.iznos;
this->d=c.d;
}
friend ostream & operator<<(ostream & out, const Transaction & c) {
if(c.iznos>0) {
return out << "Inflow " << c.iznos << " " << c.ime << "(" << c.smetka << ")-" << c.d.getDay() << "." << c.d.getMonth() << "." << c.d.getYear() << endl;
} else {
return out << "Outflow " << c.iznos << " " << c.ime << "(" << c.smetka << ")-" << c.d.getDay() << "." << c.d.getMonth() << "." << c.d.getYear() << endl;
}
}
Transaction(char * ime, char * smetka) {
this->ime = new char[strlen(ime)+1];
strcpy(this->ime,ime);
strcpy(this->smetka,smetka);
}
};
class TransactionAccount {
private:
char * ime;
char smetka[16];
Transaction * t;
int n;
int kapacitet;
public:
TransactionAccount() {
this->t = new Transaction[3];
this->kapacitet=3;
}
TransactionAccount(char * ime,char * smetka) {
this->ime = new char[strlen(ime)+1];
strcpy(this->ime,ime);
strcpy(this->smetka,smetka);
}
void addTransaction(Transaction & a) {
if(n<kapacitet) {
this->t = &a;
} else {
kapacitet*=2;
this->t = &a;
}
}
Transaction getTransList() {
return *t;
}
int getTransCapacity() {
return this->kapacitet;
}
int getTransNumber() {
return this->n;
}
virtual ~TransactionAccount() {}
};
int main() {
char name[50],number[16];
float amount;
int d,m,y;
int n;
bool isInflow;
TransactionAccount ta;
int testcase;
cin>>testcase;
switch (testcase) {
case 1: {
cout<<"------Transaction test------"<<endl;
cin>>name;
cin>>number;
cin>>amount;
cin>>d>>m>>y;
Transaction t(name,number,amount,Date(d,m,y));
cout<<t;
}
break;
case 2: {
cout<<"------TransactionAccount test:constructor, desctuctor & get-
functions------"<<endl;
cin>>name;
cin>>number;
TransactionAccount ta(name,number);
cin>>n;
for (int j=0; j<n; j++) {
cin>>name>>number>>amount>>d>>m>>y;
Transaction t(name,number,amount,Date(d,m,y));
ta.addTransaction(t);
}
cout<<"Capacity: "<<ta.getTransCapacity()<<endl;
cout<<"Number of elements: "<<ta.getTransNumber()<<endl;
cout<<(ta.getTransList())[n]; // -- here is the
problem
cin>>n;
cout<<"The element on position "<<n<<" is "<<endl;
}
return 0;
}
My desired result is that it calls the previous object(of the class) and prints it.
The answer to this specific question is that getTransList returns a single Transaction (rather than, as the name would suggest, the 'list'). The error then happens because Transaction does not have an overloaded subscript operator (which is fine; it probably shouldn't).
Transaction getTransList() {
return *t;
}
should be replaced with
Transaction* getTransList() {
return t;
}
which properly returns the array.
However, there are many other problems with the code provided. Some will become apparent when you try to run/debug the code; for the rest, while you can of course ask (new) questions about specific problems on this site, you might be better served consulting your teacher.

Access Elements of Vector - C++

I have the following class:
class Friend
{
public:
Friend();
~Friend(){}
void setName(string friendName){ name = friendName; }
void setAge(int friendAge) { age = friendAge; }
void setHeight(int friendHeight) { height = friendHeight; }
void printFriendInfo();
private:
string name;
int age;
float height;
};
//implementations
Friend::Friend()
{
age = 0;
height = 0.0;
}
//printing
void Friend::printFriendInfo()
{
cout << "Name : " << name << endl;
cout << "Age : " << age << endl;
cout << "Height : " << height << endl << endl;
}
And At this moment I can introduce the values in a vector, like this:
std::vector<Friend> regist(4, Friend());
regist[1].setAge(15);
regist[1].setHeight(90);
regist[1].setName("eieiei");
regist[2].setAge(40);
regist[2].setHeight(85);
regist[2].setName("random");
In debug, this solution works fine. But now I am trying to print the vector. So far without success.
for (int i = 0; i < regist.size(); i++) {
cout << regist[i]; //<-- error here
cout << '\n';
}
You might redesign a bit (in essence):
#include <iostream>
class Friend
{
public:
Friend();
// A more general name, const, and taking a stream.
void write(std::ostream&) const;
private:
std::string name;
int age;
float height;
};
Friend::Friend()
{
age = 0;
height = 0.0;
}
void Friend::write(std::ostream& stream) const
{
stream << "Name : " << name << std::endl;
stream << "Age : " << age << std::endl;
stream << "Height : " << height << std::endl << std::endl;
}
// Forward to the member function
inline std::ostream& operator << (std::ostream& stream, const Friend& object) {
object.write(stream);
return stream;
}
int main() {
Friend f;
std::cout << f;
}
Just call the printFriendInfo() member function:
for (int i = 0; i < regist.size(); i++) {
regist[i].printFriendInfo();
}
For
cout << regist[i];
to work, add a few accessor functions in Friend
string getName() const { return name; }
int getAge() const { return age; }
float getHeight() const { return height; }
and implement an overloaded operator<< function:
std::ostream& operator<<(std::ostream& out, Friend const& f)
{
out << "Name : " << f.getName() << std::endl;
out << "Age : " << f.getAge() << std::endl;
out << "Height : " << f.getHeight() << std::endl;
return out;
}

Segmentation fault overloading operator <<

My code compiles fine. But when i try to use my overloaded operator<< - app crashes. I didn't find any decisions by myself.If i don't use this operator everything works just fine. For example, i can pass negative argument to constructor and it will show a message using class data pointer 'company'. Debugger shows that programm crashes at this line:
os << "Company: " << s.company
in function:
std::ostream& operator<<(std::ostream& os, const Stock& s)
{
using std::ios_base;
// set format to #.###
ios_base::fmtflags orig =
os.setf(ios_base::fixed, ios_base::floatfield);
std::streamsize prec = os.precision(3);
os << "Company: " << s.company
<< " Shares: " << s.shares << '\n';
os << " Share Price: $" << s.share_val;
// set format to #.##
os.precision(2);
os << " Total Worth: $" << s.total_val << '\n';
// restore original format
os.setf(orig, ios_base::floatfield);
os.precision(prec);
return os;
}
Here's the code:
// stock20.h -- augmented version
#ifndef STOCK20_H_
#define STOCK20_H_
#include <iostream>
class Stock
{
private:
char* company;
int shares;
double share_val;
double total_val;
void set_tot() { total_val = shares * share_val; }
public:
Stock(); // default constructor
Stock(const char* co, long n = 0, double pr = 0.0);
~Stock(); // do-nothing destructor
void buy(long num, double price);
void sell(long num, double price);
void update(double price);
const Stock & topval(const Stock & s) const;
friend std::ostream& operator<<(std::ostream& os, const Stock& s);
};
#endif
Realisation:
// stock20.cpp -- augmented version
#include "stock20.h"
#include <cstring>
#define my_delete(x){ delete[] x; x = NULL; }
using namespace std;
// constructors
Stock::Stock() // default constructor
{
company = new char[1];
company[0] = '\0';
shares = 0;
share_val = 0.0;
total_val = 0.0;
}
Stock::Stock(const char* co, long n, double pr)
{
company = new char[strlen(co)+1];
strcpy(company,co);
if (n < 0)
{
std::cout << "Number of shares can't be negative; "
<< company << " shares set to 0.\n";
shares = 0;
}
else
shares = n;
share_val = pr;
set_tot();
}
// class destructor
Stock::~Stock() // quiet class destructor
{
my_delete(company);
}
// other methods
void Stock::buy(long num, double price)
{
if (num < 0)
{
std::cout << "Number of shares purchased can't be negative. "
<< "Transaction is aborted.\n";
}
else
{
shares += num;
share_val = price;
set_tot();
}
}
void Stock::sell(long num, double price)
{
using std::cout;
if (num < 0)
{
cout << "Number of shares sold can't be negative. "
<< "Transaction is aborted.\n";
}
else if (num > shares)
{
cout << "You can't sell more than you have! "
<< "Transaction is aborted.\n";
}
else
{
shares -= num;
share_val = price;
set_tot();
}
}
void Stock::update(double price)
{
share_val = price;
set_tot();
}
std::ostream& operator<<(std::ostream& os, const Stock& s)
{
using std::ios_base;
// set format to #.###
ios_base::fmtflags orig =
os.setf(ios_base::fixed, ios_base::floatfield);
std::streamsize prec = os.precision(3);
os << "Company: " << s.company
<< " Shares: " << s.shares << '\n';
os << " Share Price: $" << s.share_val;
// set format to #.##
os.precision(2);
os << " Total Worth: $" << s.total_val << '\n';
// restore original format
os.setf(orig, ios_base::floatfield);
os.precision(prec);
return os;
}
const Stock & Stock::topval(const Stock & s) const
{
if (s.total_val > total_val)
return s;
else
return *this;
}
And the code usage:
// usestok2.cpp -- using the Stock class
// compile with stock20.cpp
#include "stock20.h"
const int STKS = 4;
int main()
{{
//create an array of initialized objects
Stock stocks[STKS] = {
Stock("NanoSmart", 12, 20.0),
Stock("Boffo Objects", 200, 2.0),
Stock("Monolithic Obelisks", 130, 3.25),
Stock("Fleep Enterprises", 60, 6.5)
};
std::cout << "Stock holdings:\n";
int st;
for (st = 0; st < STKS; st++)
std::cout<<stocks[STKS]; //here we got an error
// set pointer to first element
const Stock * top = &stocks[0];
for (st = 1; st < STKS; st++)
top = &top->topval(stocks[st]);
// now top points to the most valuable holding
std::cout << "\nMost valuable holding:\n";
std::cout<<*top;}
// std::cin.get();
return 0;
}
If since i asked 1 question, i hope you don't mind me asking another one. How can i avoid using includes in headers. For example for overloaded operator<< i need to include iostream cause it has return value of ostream& type and a parameter of the same type. Thanks in advance.
When you declare an array:
Stock stocks[STKS] = ...
the array elements are indexed 0 through STKS - 1. When you access stocks[STKS] in this line:
std::cout<<stocks[STKS]; // Out-of-bounds: STKS > STKS - 1
you're accessing a non-existent array element, which is causing the crash. Given the context, you probably want std::cout<<stocks[st]; instead (hat tip: #gx_).