重载运算符 << 在使用虚函数后无法正常工作。如何解决这个问题?是因为class继承/合成?

Overloaded operator<< not working good after using virtual function. How to solve this ? It's because of class inheritance/ composition?

我的代码有问题,关于我的虚函数和 input/output 运算符,我不知道如何解决。

提前致歉,这篇文章很长。

首先我创建了 2 个 classes(继承)。 Class A 和 B 喜欢这样 :

class A{

protected:
    int x;

public:

    A()
    {
        x=0;
    }

    A(int x1)
    {
        x=x1;
    }

    A(const A &o1)
    {
        x=o1.x;
    }

    A &operator=(const A &o1)
    {
      x=o1.x;
    }

    friend istream &operator>>(istream &input, A &o1)
    {
        input >> o1.x;
        return input;
    }
    friend ostream &operator<<(ostream &output, const A &o1)
    {
        output << o1.x;
        return output;
    }
    virtual void cin2()
     {
         cin >> *this;
     }

    friend class C;
};


class B: public A{

protected:
    float y;

public:
    B(): A()
    {
        y=0.0;
    }

    B(int x1, float y1): A(x1)
    {
        y=y1;
    }

    B(const B &o2): A(o2)
    {
        y=o2.y;
    }

    B &operator=(const B &o2)
    {
        y=o2.y;
        A::operator=(o2);
        return *this;
    }

     friend istream &operator>>(istream &input, B &o2)
    {
        input >> (A&) o2;
        input >> o2.y;
        return input;
    }
    friend ostream &operator<<(ostream &output, const B &o2)
    {
        output << (A) o2;
        output << o2.y;
        return output;
    }

     void cin2()
     {
         cin >> *this;
     }
};

经过测试的输出和输入运算符在这 2 个 class 中运行良好。下面使用 虚方法(那里有解释)

接下来,我想要一个 class,里面有一个来自 class A 的 object。我阅读了有关作文的内容,并尝试做类似的事情。这是 class C:

class C{

protected:
    A* obj;
    double z;

public:
    C()
    {
        obj=new A;
        z=0;
    }

    C(double z1, const A &obj1)
    {
        obj=new A(obj1);
        z=z1;
    }

    C(const C &o3)
    {
        obj=o3.obj;
        z=o3.z;
    }

    C &operator=(const C &o3)
    {
        obj=o3.obj;
        z=o3.z;
        return *this;
    }

    friend istream &operator>>(istream &input, C &o3)
    {
        input >> o3.z;
        B obj2;
        o3.obj=&obj2;
        o3.obj->cin2();
        return input;
    }

    friend ostream &operator<<(ostream &output, const C &o3)
    {
        output << o3.z << '\n';
        operator<<(output, (B&)o3.obj);
        output << '\n';
        return output;
    }
};

问题来了。 正如我上面所说,我写了一个 虚函数 并在这里调用它,因为:

当我读( cin >>) a class C object 时,我也会自动读一个class A object。我想要的是通过 class A 到他的 child、class B 和 cin(读取)两个 classes 参数。 (因为 class B 运算符 >> 也用于 cin class A 参数)。

有效(每次我读取 class C object 时,它还需要我输入 class A 和 B 参数的值)。 没有用的是打印我刚刚阅读的内容 ( cout << )。我 运行 代码,它打印我 class C 参数(double z)但是在那之后,当它应该打印给 class A 和 B 参数的值时,它打印某种地址(我指定 o3.obj 现在是 class (B&) ,我认为它不应该那样做,虽然我不是很确定) 我怎样才能让它正常工作?

这是主要的:

int m;
    cin >>m;
    C* v=new C[m+1];

    for(int i=1; i<=m;++i)
        cin >> v[i];
    cout << '\n';
    for(int i=1;i<=m;++i)
        cout << v[i];
    return 0;

我的输入:

1  /// numbers of objects
10 /// class C parameter (float z)
11 /// class A parameter (int x)
10.1 /// Class B parameter (float y)

My output: 

10 /// value of class C parameter
494590 /// ? some address

现在,您可能认为如果 class C 在 class B 内部有一个 object 会更容易(这样就不需要虚函数,因为如果我们使用 class B 输入(cin >>),它也会自动读取 class A 参数的值。)好吧,它更容易,但不能满足我的要求。另外,我读到了关于向下转换的内容,dynamic_cast,这可能是我如何以一种聪明的方式解决这个问题的方法,但我不明白在哪里以及如何使用 dynamic_cast。

如果你也能用一些例子回答我(以便更好地理解在这里做什么),我将不胜感激。 可能答案很简单,我太笨了,自己找不到

我很高兴找到答案。如果有时间,请帮帮我。

我重新编写了您的代码以演示您需要做什么。我删除了 istream 部分,但应用于 ostream 代码的原则是相同的。因为 operator<<()operator>>() 而不是 成员函数,所以您不能直接从它们获得多态行为。您可以做的就是让它们调用具有多态行为的成员函数。

使这项工作起作用的另一部分是一个新的 C 构造函数,它将指向 A 的指针作为参数。这允许我使用指向 AA.

的任何子对象 class 的指针来初始化 C 对象

您还会注意到我对代码做了很多其他的小改动。我应用了一些更好的做法(默认成员初始化、初始化部分的完整使用等)并删除了不必要的函数。这些 classes 不需要复制构造函数和赋值运算符重载。

#include <iostream>
#include <memory>

class A {
 protected:
  int x = 0;

  virtual void print(std::ostream &sout) const { sout << x << '\n'; }

 public:
  A() = default;
  A(int x1) : x(x1) {}
  virtual ~A() = default;

  friend std::ostream &operator<<(std::ostream &output, const A &o1) {
    o1.print(output);

    return output;
  }
};

class B : public A {
 protected:
  float y = 0.0f;

  void print(std::ostream &sout) const override {
    sout << y << '\n';
    A::print(sout);
  }

 public:
  B() : A() {}
  B(int x1, float y1) : A(x1), y(y1) {}

  friend std::ostream &operator<<(std::ostream &output, const B &o2) {
    o2.print(output);

    return output;
  }
};

class C {
 protected:
  double z = 0.0;
  std::unique_ptr<A> obj{nullptr};

 public:
  C() = default;
  C(double z1, const A &obj1) : z(z1), obj(new A(obj1)) {}
  C(double z1, A *ptrA) : z(z1), obj(ptrA) {}  // Newly added
  C(const C &o3) : z(o3.z), obj(new A(*(o3.obj))) {}

  friend std::ostream &operator<<(std::ostream &output, const C &o3) {
    output << o3.z << '\n';
    output << *(o3.obj);

    return output;
  }
};

int main() {
  C c(3.14, new B(5, 2.3f));
  std::cout << c << '\n';

  A a(8);
  C c2(4.5, a);
  std::cout << c2 << '\n';

  return 0;
}

输出:

3.14
2.3
5

4.5
8