如何改进我的 class 的运算符重载?
How to improve operator overloading for my class?
我开始学习C++了。我的老师布置了作业。我完成了它(留下了一些润色工作)并且一切似乎都有效但存在冗余。我的主要问题是超载。
如何改善我的 class 中的过载。与其编写所有四个函数(两个用于 fstream,两个用于 iostream),是否可以只编写两个?还有其他进一步改进代码的建议吗?
#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;
}
这里你只需要两个重载。 ifstream
和 ofstream
分别继承自 istream
和 ostream
所以如果你有
friend istream& operator >> (istream &is, book& obj);
friend ostream& operator << (ostream &os, const book& obj);
那么它们将与 cout
和 cin
以及任何 fstream
或 stringstream
对象一起使用,因为它们也继承自 istream
和 ostream
.
除了只为 std::istream
和 std::ostream
重载之外的一些其他建议:
- 不要
using namespace std;
。最好在 STL 类型和算法前加上 std::
.
- 更喜欢
using
而不是 typedef
,在这种情况下,更喜欢 #define
。您可以将 usi
别名限制在 book
范围内。
- 将
book
转换为结构:如果 class book
中的所有内容都是 public。这样,您不需要运算符重载成为 book
的友元,因为它们可以直接访问 book
实例中的成员。
- Prefer to use member initialization lists,即在参数列表之后立即初始化您的成员变量。您还可以在声明点提供一个默认的成员初始化值;但是,在这种情况下,单个
{}
将零初始化 usi
类型。在此示例中,我不会为构造函数使用默认参数值。
- 考虑到,如果您提供自定义构造函数,默认构造函数、复制构造函数、移动构造函数、复制赋值运算符和移动赋值运算符将被删除,因此不可用。
#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;
}
- 将
book
设为 aggregate。如果您忘记将 std::string
成员初始化为 "NONE"
(您始终可以在 operator<<
处检查空字符串并在需要时输出 "NONE
,则可以摆脱很多代码).您摆脱了自定义构造函数以及所有其他默认构造函数和赋值运算符。
#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;
}
我开始学习C++了。我的老师布置了作业。我完成了它(留下了一些润色工作)并且一切似乎都有效但存在冗余。我的主要问题是超载。 如何改善我的 class 中的过载。与其编写所有四个函数(两个用于 fstream,两个用于 iostream),是否可以只编写两个?还有其他进一步改进代码的建议吗?
#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;
}
这里你只需要两个重载。 ifstream
和 ofstream
分别继承自 istream
和 ostream
所以如果你有
friend istream& operator >> (istream &is, book& obj);
friend ostream& operator << (ostream &os, const book& obj);
那么它们将与 cout
和 cin
以及任何 fstream
或 stringstream
对象一起使用,因为它们也继承自 istream
和 ostream
.
除了只为 std::istream
和 std::ostream
重载之外的一些其他建议:
- 不要
using namespace std;
。最好在 STL 类型和算法前加上std::
. - 更喜欢
using
而不是typedef
,在这种情况下,更喜欢#define
。您可以将usi
别名限制在book
范围内。 - 将
book
转换为结构:如果 classbook
中的所有内容都是 public。这样,您不需要运算符重载成为book
的友元,因为它们可以直接访问book
实例中的成员。 - Prefer to use member initialization lists,即在参数列表之后立即初始化您的成员变量。您还可以在声明点提供一个默认的成员初始化值;但是,在这种情况下,单个
{}
将零初始化usi
类型。在此示例中,我不会为构造函数使用默认参数值。 - 考虑到,如果您提供自定义构造函数,默认构造函数、复制构造函数、移动构造函数、复制赋值运算符和移动赋值运算符将被删除,因此不可用。
#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;
}
- 将
book
设为 aggregate。如果您忘记将std::string
成员初始化为"NONE"
(您始终可以在operator<<
处检查空字符串并在需要时输出"NONE
,则可以摆脱很多代码).您摆脱了自定义构造函数以及所有其他默认构造函数和赋值运算符。
#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;
}