简体   繁体   English

在C ++中继承和重写ostream运算符

[英]Inheriting and overriding ostream operator in C++

I've been trying to find an answer to this, but no one seems to have exactly the same problem as I do. 我一直在试图找到答案,但是似乎没有人遇到与我完全相同的问题。

I am working with several derived classes. 我正在处理几个派生类。 The ostream operator << for each of these should print out some things common to each, and some things specific to each. ostream运算符<<对于其中的每一项都应打印出某些通用的内容,以及某些特定的内容。 Later on, I would like to further derive from these derived classes, and again the new derived classes need to print out some things that are in the "generations" above them. 稍后,我想进一步从这些派生类派生,而新的派生类又需要打印出它们上方“世代”中的某些内容。
For example: 例如:

The Base class .h file 基类.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;

};

The Base.cpp file includes these lines: Base.cpp文件包括以下几行:

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

Then I derive: (FirstDerived.h) 然后我得出:(FirstDerived.h)

class FirstDerived : Public Base

{ 

int SecondClassNumber;

};

FirstDerived.cpp: 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;
}

Then I want to derive: 然后我想得出:

class SecondDerived: Public FirstDerived
{ 

int ThirdClassNumber;

};

Second.cpp: Second.cpp:

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

 FirstDerived::operator<<

 << "The third number is "

 << ThirdClassNumber;

 }

I think the problem is most likely either the declaration in the very start of the program, or the lines like Base::operator<< . 我认为问题很可能是程序开始时的声明,或者是Base::operator<<类的行。

Another possibility is that I'm not redeclaring it in the .h file of every inherited class. 另一种可能性是,我没有在每个继承的类的.h文件中重新声明它。 Should I be, and if so what syntax should I use? 应该是,如果是,应该使用什么语法?

It was suggested to me to use the static_cast method, but my professor (the one who wrote the assignment, and therefore won't give us too much help with it) said that there's a better way to do it. 有人建议我使用static_cast方法,但是我的教授( static_cast的人,因此不会给我们太多帮助)表示,有更好的方法。 Any suggestions? 有什么建议么?

A simple technique for this is: 一个简单的技术是:

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

You cannot implement operator<< for ostreams as a class member - it has to be a free (possibly friend) function. 您不能将ostreams的operator <<作为类成员实现-它必须是一个免费的(可能是朋友)函数。 This is because in the expression: 这是因为在表达式中:

os << x;

the thing on the left-hand side of the << will not be an instance of your class, which it would have to be if it were a member function. <<左侧的东西将不是您的类的实例,如果它是成员函数则必须是它的实例。

To call the parent from the child - do a static_cast: 要从子级调用父级,请执行static_cast:

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

which I think is the "best" solution. 我认为这是“最佳”解决方案。 Alternatively, give your classes aa named function call Print() which takes an ostream as a parameter and use this to implement your operator<<. 或者,为类提供一个名为函数的调用Print(),该函数将ostream作为参数,并使用此函数实现您的operator <<。 This will result in much cleaer code. 这将导致大量的透明代码。

Aside from what @Neil says, it would probably be better to implement a virtual DoStream method, so you don't need the upcasting: 除了@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
  }
};

So you only need to implement the operator once. 因此,您只需实施一次操作员。 You could also make the operator<< non-friend and the DoStream public, but that is probably personal preference. 您还可以将operator<< DoStream非朋友,并公开DoStream ,但这可能是个人喜好。

FirstDerived.cpp: 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;
}

You need to call the function by putting parenthesis after it, and provide the argument it expects. 您需要通过在函数后面加上括号来调用函数,并提供期望的参数。 It doesn't have a return value so shouldn't be in the set of things being streamed. 它没有返回值,因此不应放在正在流式传输的事物集中。 Summarily: 总结:

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

Here's a slight modification to Loki's answer. 这是对Loki答案的略微修改。 Instead of having a virtual serialize method, I use a virtual to_string method. 我没有虚拟的序列化方法,而是使用虚拟的to_string方法。 I think this can be reused in more contexts outputing to an ostream, which might be of use. 我认为这可以在输出到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;
}

Produces 产生

Base: 1 
FirstDerived: 1 2

To call a method from base class you can use: 要从基类调用方法,可以使用:

Base::method(/*parameters*/)

But operator<< is a free function. 但是operator<<是一个自由函数。 The only possibility without static_cast I can see is to define the operator as a template and then explicitly call the specialization like this: 我看不到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 ...
}

This could be done the same way for operator<<, just change the name function for operator<< and add required parameters. 这可以做同样的方式进行操作<<,只是将名称更改functionoperator<<并添加所需的参数。


Another possibility is to make a virtual member function: 另一种可能性是使虚拟成员函数:

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

In Derived class this could call the Base print function: 在派生类中,可以调用基本打印功能:

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

Then it is enough to have operator<< only for the Base class and it will call appropriate print method polymorphicaly. 这样,仅对Base类具有operator<<就足够了,它将调用适当的打印方法多态性。 Note that the operator<< is a free function. 请注意, operator<<是自由函数。

ostream &operator<< (ostream &os, Base const &b) {
    b.print(os);
    return os;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM