如何改进我的 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;
}

这里你只需要两个重载。 ifstreamofstream 分别继承自 istreamostream 所以如果你有

friend istream& operator >> (istream &is, book& obj);
friend ostream& operator << (ostream &os, const book& obj);

那么它们将与 coutcin 以及任何 fstreamstringstream 对象一起使用,因为它们也继承自 istreamostream.

除了只为 std::istreamstd::ostream 重载之外的一些其他建议:

  • 不要 using namespace std;。最好在 STL 类型和算法前加上 std::.
  • 更喜欢 using 而不是 typedef,在这种情况下,更喜欢 #define。您可以将 usi 别名限制在 book 范围内。
  • book 转换为结构:如果 class book 中的所有内容都是 public。这样,您不需要运算符重载成为 book 的友元,因为它们可以直接访问 book 实例中的成员。
  • Prefer to use member initialization lists,即在参数列表之后立即初始化您的成员变量。您还可以在声明点提供一个默认的成员初始化值;但是,在这种情况下,单个 {} 将零初始化 usi 类型。在此示例中,我不会为构造函数使用默认参数值。
  • 考虑到,如果您提供自定义构造函数,默认构造函数、复制构造函数、移动构造函数、复制赋值运算符和移动赋值运算符将被删除,因此不可用。

[Demo]

#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,则可以摆脱很多代码).您摆脱了自定义构造函数以及所有其他默认构造函数和赋值运算符。

[Demo]

#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;
}