I have started learning C . My teacher gave an assignment. I completed it (some polishing work is left) and everything seems to work but there is redundancy. My major issue is overloading. How to improve overloading in my class. Rather than writing all four functions (two for fstream and two for iostream), is it possible to write only two ? Any other suggestions to improve the code further ?
#include <iostream>
#include <fstream>
#include <string>
#include "../../my_func.hpp"
#define usi unsigned short int
using namespace std;
class book
{
public:
usi book_id = 0, price = 0, no_of_pages = 0, year_of_publishing = 0;
string author_name = "NONE", publisher = "NONE";
book(usi b_id = 0, usi b_price = 0, usi b_no_of_pages = 0, usi b_year_of_publishing = 0,
const string& b_author_name = "NONE", const string& b_publisher = "NONE")
{
book_id = b_id;
price = b_price;
no_of_pages = b_no_of_pages;
year_of_publishing = b_year_of_publishing;
author_name = b_author_name;
publisher = b_publisher;
}
friend fstream& operator >> (fstream& is, book& obj);
friend fstream& operator << (fstream& os, const book& obj);
friend istream& operator >> (istream &is, book& obj);
friend ostream& operator << (ostream &os, const book& obj);
};
fstream& operator >> (fstream &is, book& obj)
{
char ch;
is >> obj.book_id >> obj.price
>> obj.no_of_pages >> obj.year_of_publishing;
is.ignore(1, '\n'); //To take care of new line character
getline(is, obj.author_name);
getline(is, obj.publisher);
return is;
}
fstream& operator << (fstream &os, const book& obj)
{
os.operator<<(obj.book_id) << '\n' //calling operator function cuz it works
<< obj.price << '\n'
<< obj.no_of_pages << '\n'
<< obj.year_of_publishing << '\n';
os << obj.author_name << '\n'
<< obj.publisher << '\n';
return os;
}
istream& operator >> (istream &is, book& obj)
{
is >> obj.book_id >> obj.price
>> obj.no_of_pages >> obj.year_of_publishing;
is.ignore(1, '\n'); //To take care of new line character
getline(is, obj.author_name);
getline(is, obj.publisher);
return is;
}
ostream& operator << (ostream &os, const book& obj)
{
os << obj.book_id << '\n'
<< obj.price << '\n'
<< obj.no_of_pages << '\n'
<< obj.year_of_publishing << '\n'
<< obj.author_name << '\n'
<< obj.publisher << '\n';
return os;
}
int main()
{
string path = ".\\C _Experiment\\Exp-7\\Files\\Source.txt";
book b1(12, 3000, 100, 2003, "Lol", "Pew"), b2, b3;
fstream fio;
fio.open(path, ios::out | ios::app | ios::in);
if(fio) fio << b1;
else cout << "error";
fio.seekg(0, ios::beg);
if(fio) fio >> b2 >> b3;
cout << b2 << b3;
fio.close();
cout << "DONE";
return 0;
}
CodePudding user response:
You only need two overloads here. ifstream
and ofstream
inherit from istream
and ostream
respectively so if you have
friend istream& operator >> (istream &is, book& obj);
friend ostream& operator << (ostream &os, const book& obj);
then those will work with cout
and cin
, and any fstream
or stringstream
objects as they also inherit from istream
and ostream
.
CodePudding user response:
Some other suggestions apart from overloading only for std::istream
and std::ostream
:
- Don't
using namespace std;
. Prefer to prefix your STL types and algorithms withstd::
. - Prefer
using
totypedef
, and, in this case, to#define
. You could limit theusi
alias to thebook
scope. - Turn
book
into a struct: if everything within the classbook
is public. This way, you don't need the operator overloads to be friends ofbook
, since they can directly access the members within abook
instance. - Prefer to use member initialization lists, i.e. initialize your member variables right after the list of parameters. You can also provide a default member initialization value at the declaration point; but, in this case, a single
{}
will zero initialize theusi
types. I wouldn't use default parameter values for the constructor in this example. - Consider that, if you provide a custom constructor, the default constructor, copy constructor, move constructor, copy assignment operator, and move assignment operator will be deleted, and thus not available.
#include <iostream>
#include <string>
struct book {
using usi = unsigned short int;
usi book_id{};
usi price{};
usi no_of_pages{};
usi year_of_publishing{};
std::string author_name{"NONE"};
std::string publisher{"NONE"};
book() = default;
book(const book& other) = default;
book& operator=(const book& other) = default;
book(book&& other) noexcept = default;
book& operator=(book& other) noexcept = default;
~book() = default;
book(usi b_id,
usi b_price,
usi b_no_of_pages,
usi b_year_of_publishing,
const std::string& b_author_name,
const std::string& b_publisher)
: book_id{b_id}
, price{b_price}
, no_of_pages{b_no_of_pages}
, year_of_publishing{b_year_of_publishing}
, author_name{b_author_name}
, publisher{b_publisher}
{}
};
std::istream& operator>>(std::istream& is, book& obj) {
is >> obj.book_id >> obj.price >> obj.no_of_pages >> obj.year_of_publishing;
is.ignore(1, '\n'); // To take care of new line character
getline(is, obj.author_name);
getline(is, obj.publisher);
return is;
}
std::ostream& operator<<(std::ostream& os, const book& obj) {
return os
<< "["
<< obj.book_id << ", "
<< obj.price << ", "
<< obj.no_of_pages << ", "
<< obj.year_of_publishing << ", "
<< obj.author_name << ", "
<< obj.publisher << "]";
}
int main() {
book b1{ 12, 3000, 100, 2003, "Lol", "Pew" };
std::cout << "b1: " << b1 << "\n";
book b2{};
std::cin >> b2;
std::cout << "b2: " << b2;
}
- Make
book
an aggregate. You can get rid of a lot of code if you forget about initializing thestd::string
members to"NONE"
(you can always check for empty string atoperator<<
and output"NONE
if needed). You get rid of the custom constructor and, with it, of all the other default constructors and assignment operators.
#include <iostream>
#include <string>
struct book {
using usi = unsigned short int;
usi book_id{};
usi price{};
usi no_of_pages{};
usi year_of_publishing{};
std::string author_name{};
std::string publisher{};
};
std::istream& operator>>(std::istream& is, book& obj) {
is >> obj.book_id >> obj.price >> obj.no_of_pages >> obj.year_of_publishing;
is.ignore(1, '\n'); // To take care of new line character
getline(is, obj.author_name);
getline(is, obj.publisher);
return is;
}
std::ostream& operator<<(std::ostream& os, const book& obj) {
return os
<< "["
<< obj.book_id << ", "
<< obj.price << ", "
<< obj.no_of_pages << ", "
<< obj.year_of_publishing << ", "
<< (obj.author_name.empty() ? "NONE" : obj.author_name) << ", "
<< (obj.publisher.empty() ? "NONE" : obj.publisher) << "]";
}
int main() {
book b1{ 12, 3000, 100, 2003, "Lol", "" };
std::cout << "b1: " << b1 << "\n";
book b2{};
std::cin >> b2;
std::cout << "b2: " << b2;
}