8

我一直在努力寻找答案,但似乎没有人遇到与我完全相同的问题。

我正在使用几个派生类。每一个的 ostream 操作符 << 应该打印出一些共同的东西,以及一些特定的东西。稍后,我想进一步从这些派生类中派生出来,并且新的派生类再次需要打印出它们上面“世代”中的一些东西。
例如:

基类 .h 文件

class Base

{  



 int FirstClassNumber;

//The declaration I'm currently working with, that a friend gave me
//I'm pretty sure my problem lies here.


public:

friend ostream& operator << (ostream& os, const Base &base)
{
    base << os ;

    return os;
}

virtual void operator << (ostream& os) const = 0;

};

Base.cpp 文件包括以下几行:

void Base::operator << (ostream& os)
{
  os << FirstClassNumber;
}

然后我得出:(FirstDerived.h)

class FirstDerived : Public Base

{ 

int SecondClassNumber;

};

FirstDerived.cpp:

FirstDerived::operator << (ostream& os)
{
  os <<

  "The first Number is:

 //This is the line that isn't working - someone else gave me this syntax

  << Base::operator<< 

  << "The second number is"

  << SecondClassNumber;
}

然后我想得出:

class SecondDerived: Public FirstDerived
{ 

int ThirdClassNumber;

};

第二个.cpp:

FirstDerived::operator << (ostream& os)
{
  os <<

 FirstDerived::operator<<

 << "The third number is "

 << ThirdClassNumber;

 }

我认为问题很可能是程序一开始的声明,或者像Base::operator<<.

另一种可能性是我没有在每个继承类的 .h 文件中重新声明它。我应该是,如果是,我应该使用什么语法?

有人建议我使用这种static_cast方法,但我的教授(写作业的人,因此不会给我们太多帮助)说有更好的方法来做。有什么建议么?

4

6 回答 6

16

一个简单的技术是:

class Base
{  
    int FirstClassNumber;

    public:
        virtual void serialize(ostream& os) const
        {
             os << FirstClassNumber;
        }
};

// Implement the stream operator for the base class.
// All it does is call erialize which is a virtual method that
// will call the most derived version.
ostream& operator << (ostream& os, const Base &base)
{
    base.serialize(os);

    return os;
}

class FirstDerived:public Base
{  
    int SecondClassNumber;

    public:
        // Override serialize to make it call the base version.
        // Then output any local data.
        virtual void serialize(ostream& os) const
        {
             Base::serialize(os);
             os << SecondClassNumber;
        }
};
于 2011-05-17T07:27:55.623 回答
6

您不能将 ostreams 的 operator<< 实现为类成员 - 它必须是免费的(可能是朋友)函数。这是因为在表达式中:

os << x;

<< 左边的东西不是你的类的实例,如果它是一个成员函数,它就必须是。

从孩子调用父母 - 做一个static_cast:

ostream & operator << ( ostream & os, const Child & c ) {
      os << static_cast <const Parent &>( c );
      // child stuff here
}

我认为这是“最佳”解决方案。或者,给你的类一个命名函数调用 Print(),它接受一个 ostream 作为参数并使用它来实现你的 operator<<。这将导致更清晰的代码。

于 2011-05-17T07:03:38.660 回答
3

除了@Neil 所说的,实现一个虚拟DoStream方法可能会更好,所以你不需要向上转换:

class Base{
private:
  virtual void DoStream(ostream& os){
    // general stuff
  }
public:
  friend ostream& operator<<(ostream& os, Base& b){
    b.DoStream(os);
    return os;
  }
};

class Derived : public Base{
private:
  void DoStream(ostream& os){
    Base::DoStream(os);
    // derived specific stuff
  }
};

所以你只需要实现一次操作符。您也可以让operator<<非朋友和公众成为DoStream公众,但这可能是个人喜好。

于 2011-05-17T07:20:17.110 回答
1

FirstDerived.cpp:

FirstDerived::operator << (ostream& os)
{
     os <<    "The first Number is:"
   //This is the line that isn't working - someone else gave me this syntax
    << Base::operator<<
     << "The second number is"
    << SecondClassNumber;
}

您需要通过在函数后面加上括号来调用函数,并提供它期望的参数。它没有返回值,因此不应该在流式传输的集合中。总结:

os << "The first number is: "; // finish streaming statement with ";"
Base::operator<<(os);   // separate statement to call this function...
os << "The second number is " << SecondClassNumber; // start streaming again
于 2011-05-17T07:34:46.220 回答
0

这是对 Loki 答案的轻微修改。我没有使用虚拟序列化方法,而是使用虚拟 to_string 方法。我认为这可以在更多输出到 ostream 的上下文中重用,这可能有用。

#include <iostream>
#include <string>

class Base
{
public:
  Base();
  virtual std::string to_string() const;

protected:
  int first_class_number;
  friend std::ostream& operator<<(std::ostream& os, const Base &base);
};

Base::Base()
  : first_class_number(1)
{
}

std::string Base::to_string() const
{
  return "Base: "+std::to_string(first_class_number);
}



class FirstDerived : public Base
{
public:
  FirstDerived();
  std::string to_string() const;

protected:
  int second_class_number;
};

FirstDerived::FirstDerived()
  : second_class_number(2)
{
}

std::string FirstDerived::to_string() const
{
  return "FirstDerived: "+std::to_string(first_class_number)+" "+ std::to_string(second_class_number);
}


std::ostream& operator << (std::ostream& os, const Base &base)
{
  os << base.to_string();
  return os;
}


int main(int argc, const char *argv[])
{
  std::cout << Base() << std::endl;
  std::cout << FirstDerived() << std::endl;
  return 0;
}

生产

Base: 1 
FirstDerived: 1 2
于 2013-03-25T14:22:43.760 回答
0

要从基类调用方法,您可以使用:

Base::method(/*parameters*/)

但是operator<<是免费功能。我可以看到没有 static_cast 的唯一可能性是将运算符定义为模板,然后像这样显式调用特化:

template<typename T>
void function(T const &t);

template<>
void function<Base>(Base const &t) {
    // own implementation ...
}

template<>
void function<Derived>(Derived const &t) {
    function<Base>(t);
    // own implementation ...
}

这可以为 operator<< 以相同的方式完成,只需更改名称并添加所需的function参数operator<<


另一种可能性是制作一个虚拟成员函数:

class Base {
    virtual void print(ostream &os) const {
        // print self
    }
}; 

在 Derived 类中,这可以调用 Base 打印函数:

class Derived {
    virtual void print(ostream &os) const {
        Base::print(os);
        // print self
    }
};

那么operator<<只对Base类就足够了,它将多态地调用适当的打印方法。请注意,这operator<<是一个免费功能。

ostream &operator<< (ostream &os, Base const &b) {
    b.print(os);
    return os;
}
于 2011-05-17T07:09:16.160 回答