为什么我不能在派生 class 运算符>> 中调用基础 class 运算符>>?

Why i can't call base class operator>> in derived class operator>>?

假设我们有 2 classes :

class base{

protected:
    char first_name;
public: 
    /// constructors , destructor, operator= overloading ...
    
    friend istream& operator >> (istream& in, base &client1) 
    {
        char f_name[1001];
        cout << "First Name: ";
        in >> f_name;
        client1=base(f_name); /// class parameterised constructor;
         
        return in;
    }
};

class derived: public base{

protected:
    char last_name[1001];
public: 
    /// constructors , destructor, operator= overloading ...
    
    friend istream& operator >> (istream& in, derived &client2) 
    {
        char l_name[1001], f_name[1001];
       
        in >> (base) client2; /// it's not working like it dose in operator<<..
        cout << "Last Name: ";
        is >> l_name;
        client2=derived(f_name, l_name); /// class parameterized constructor, 2 parameters because it use base constructor as well;
         
        return in;
    }
};

我重载了一些输出运算符 (<<),每次我从派生运算符 << 中的基调用运算符 << 时,它似乎都运行良好。

我不知道这对运算符<<是否同样有效,我尝试了一些但它给出了错误。 当我调用 base class operator>> 在 derived class operator>> 中时,它给我错误:

" no matching function for call to 'operator>>(std::istream&, abonament)'| "

同样,如果我在 operator<< 中做同样的事情,它工作正常:

friend ostream& operator << (ostream& out, derived &client) 
    {
       
        out << (base) client; /// it's working;
       
        out << client.last_name;
         
        return in;
    }

是否可以在派生的 class 运算符中调用基 class 运算符>> >>> 为什么会发生这种情况以及如何解决? (我希望我不必在派生 class 运算符>> 中再次重写基 class 运算符>> 中的相同行)

您已成为 object slicing 的牺牲品。您可以通过转换为参考来解决眼前的问题。

in >> (base) client2;

真正发生的是一个新的临时 Base 是由 client2 生成的,丢弃了 derived 的所有添加成员。这是合法的。编译器不高兴,因为临时 Base 不能用作 base &client1 参数的参数。临时变量就像它们听起来一样。它们的存在时间不长,因此引用一个是编译器阻止您犯的错误。如果它是合法的,临时变量将被 Base>> 运算符修改,然后在您可以使用读入它的内容之前立即超出范围。

in >> (base&) client2;

不分片也不做临时变量。 client2 更新成功。不幸的是,这项工作在

时被丢弃了
client2=derived(f_name, l_name);

用未初始化的变量覆盖它 l_name

因此需要进行更多更改。

不要使用构造函数来完全重新创建和重新分配您正在读入的对象。而是直接读入对象的成员变量。

示例:

class base{

protected:
    char first_name[1001]; // need more than one character
public: 
    /// constructors , destructor, operator= overloading ...
    
    friend istream& operator >> (istream& in, base &client1) 
    {
        // char f_name[1001]; don't need. Read into member
        cout << "First Name: ";
        in >> client1.first_name; // read directly into member
        // client1=base(f_name); don't need. Work done above
         
        return in;
    }
};

class derived: public base{

protected:
    char last_name[1001];
public: 
    /// constructors , destructor, operator= overloading ...
    
    friend istream& operator >> (istream& in, derived &client2) 
    {
        //char l_name[1001], f_name[1001]; don't need. Use member variables
       
        in >> (base&) client2; // client was being sliced. explanatory link above
        //         ^ fixed with reference to allow polymorphism                             
        cout << "Last Name: ";
        in >> client2.last_name; // fixed typo. reading directly into member
        // client2=derived(f_name, l_name); don't need. Work done above
         
        return in;
    }
};

旁注:这是对继承的滥用。这实际上是说姓氏 is-a first name. Which it isn't. Read up on the Liskov Substitution principle for a good rule to help determine when inheritance makes sense. Here's some starter reading: What is an example of the Liskov Substitution Principle?

旁注:>> 将一个空格分隔的标记(一个词)读入给定的 char 数组。这里有两个问题。最重要的是它不知道什么时候停止。 1001 字符数组只能部分缓解这种情况。用户需要长时间键入才能溢出缓冲区,但不要怀疑人们会为了乐趣或利益而这样做。使用 std::string 代替,问题就消失了。第二个问题是整个一个词的事情。此解析器无法处理诸如“Billy Bob”或“von Doom”之类的名称,幸运的是,该姓氏的所有者是虚构的,因为他是众所周知的不宽容。