0

我正在处理一个类,我的类中有 3 个数组,它们都代表相同的数据,但格式不同。我已经重载了<<在我的类之外声明的运算符,它接受一个 const 引用而不是这个类的朋友。

SomeClass {
public:
    // Nameless Union - All 3 Arrays Are of The Same Exact Data Type
    // And All 3 Arrays Have The Same Exact Size. This Nameless Union
    // Uses The Same Memory Address For All 3 Arrays And Their Elements. 
    // So An Element Is Changed By One Array Type, It Is Expected And 
    // Accepted For It To Change The Others. This Is Not 3 Different 
    // Arrays, This Is Still 1 Array Of Size 256, Just Different 
    // Representations Or Different Ways To Access Them.
    union {
        int m_256[256];
        int m_16[16][16];
        int m_4[4][4][4][4];
    };

    SomeClass() { std::fill( std::begin( m_256 ), std::end( m_256 ), 0 ); }

}; // SomeClass

std::ostream& operator<<( std::ostream& out, const SomeClass& c ) {
    out << std::endl;

    for ( unsigned box = 0; box < 4; box++ ) {
        for ( unsigned slice = 0; slice < 4; slice++ ) {
            for ( unsigned row = 0; row < 4; row++ ) {
                for ( unsigned col = 0; col < 4; col++ ) {
                    out << "(" << box << "," << slice << "," << row << "," << col << ") = "
                         << c.m_4[box][slice][row][col] << std::endl;
                }
            }
        }
    } 
    return out;
} // operator<<

这是我目前拥有的。我希望能够做的是也使用operator<<这个类,但能够区分以不同格式显示相同数据的方式。

我知道你不能这样做:通过添加第二个

std::ostream& operator<<( std::ostream& out, const SomeClass& c ) {
    out << std::endl;
    for ( unsigned i = 0; i < 16; i++ ) {
        for ( unsigned j = 0; j < 16; j++ ) {
            out << "(" << i << "," << j << ") = " << c.m_16[i][j] << std::endl;
        }
    }
    return out;
} // operator<<

第三个

std::ostream& operator<<( std::ostream& out, const SomeClass& c ) {
    out << std::endl;
    for ( unsigned u = 0; u < 256; u++ ) {
        out << u << " = " << m_256[u] << std::endl;
    }
    return out;
} // operator<<

由于这是模棱两可的事实。然而,我希望能够以 3 种不同格式中的任何一种显示它。

是否有任何工作或解决此问题的方法?我希望能够将类对象发送给流运算符,而这些类型的运算符不能接受附加参数,因为它们是二元运算符而不是函数。

4

5 回答 5

4

您可以只使用适配器类来编写输出。您可以将格式说明符传递给构造函数或按类型区分。例如(按类型区分):

struct SomeClassAs256 {
  SomeClass const& x_;

  explicit(SomeClass const& x) : x_(x) {}
};

然后有一个 operator<< 实现:

ostream& operator<<(ostream& os, SomeClassAs256 const& x) {
  ...
  return os;
}

然后你使用它:

SomeClass x;
...
cout << SomeClassAs256(x) << endl;
于 2016-04-08T06:21:04.980 回答
2

你不能真正做到这一点,至少不能那么简单。

这给您留下了两个选择:使用两个函数来创建字符串并返回它,或者创建一个流操纵器结构。

创建一组格式化函数返回一个字符串,然后用于输出很简单,使用std::ostringstream

std::string format1(SomeClass const& c)
{
    std::ostringstream os;
    os << whatever you want ...
    return os.str();
}

创建操纵器结构稍微复杂一些,但也可以更加灵活和强大:

class format1
{
public:
    format1(SomeClass const& c)
        : c_(c)
    {}

    friend std::ostream& operator<<(std::ostream& os,
                                    format1 const& fmt)
    {
        os << some formated output here using `fmt.c_`...;
        return os;
    }

private:
    SomeClass const& c_;
};

在这两种情况下,您都可以以相同的方式使用它:

SomeClass c(...);
std::cout << format1(c) << '\n';
于 2016-04-08T06:23:05.463 回答
1

在看到一些很好的答案并考虑到ostream对象operator<<不知道使用哪种类型并确定将由用户决定根据他们的需要显示信息后,我走了一条不同的路线;但是,我提出的适合我当前需求的解决方案得到了所有为这个问题留下了很好答案的人的帮助和启发。

我采取的方向是这样的;enum我用 3 种类型直接在我的班级中添加了一个。我添加了一个公共函数,它输出一个字符串并将enum类型作为参数。我添加ostream operator<<到我的类,它需要的参数是typename我的类enum。我使用 out 函数来分支我的 3 种不同的方式来显示信息。因此,现在在使用该对象的另一段代码中,我可以传递调用 out 函数的实例,该函数通过传入所需的类型来返回字符串。我的班级现在看起来像这样:

class SomeClass {
public:
    enum OutputType { x256, x16, x4 };

    union {
        int m_256[256];
        int m_16[16][16];
        int m_4[4][4][4][4];
    };

    std::string out( OutputType type ) const;

    std::ostream& operator<<( typename SomeClass::OutputType type );

}; // SomeClass


std::ostream& SomeClass::operator<<( typename SomeClass::OutputType type ) {
    return std::ostream << out(type );
} // operator<<

std::string SomeClass::out( OutputType type ) const {
    std::ostringstream out;
    out << std::endl;

    switch( type ) {
        case: x256: {
            // Print Format Here
            break; 
        }
        case x16: {
            // Print Format Here
            break;
        }
        case x4: {
            // Print Format Here
            break;
        }
        default: {
            // Error Message
            return out.str();
        }
    }
    return out.str();
 } // out

我不知道它是否与我的项目中的类是 atemplate或实现方式有关operator<<,但我必须typename在函数声明/定义中使用 with 才能使其工作,所以这就是我的除了类名之外的代码。

template< class T>
std::ostringstream& SomeClass<T>::operator<<( typename SomeClass<T>::Type type ) { 
    // Code Here
}

我感谢你们所有人提供的所有帮助和建议,我将这些建议铭记于心,谢谢大家。

编辑

现在,如果我想让用户更轻松一点:我可以将我的 out 函数移到私有部分;写出 3 个不带任何参数的包装器或打印函数,但它们将变量设置为私有方法。

于 2016-04-08T08:27:51.170 回答
1

您可以通过使用 make 函数从您的类返回一个代理(以提供适应)并使用: operator << (ostream, SomeClass::Proxy) 作为输出运算符来做到这一点。我将处理一些示例代码。

这样你就不需要暴露你的类的内部了。让运算符 << 成为朋友没什么错...

例子:

#include <iostream>
class SomeClass {
    union {
        int m_256[256];
        int m_16[16][16];
        int m_4[4][4][4][4];
    };
public:

    SomeClass() { std::fill( std::begin( m_256 ), std::end( m_256 ), 0 ); }

    struct x256
    {
      const SomeClass& c_;
      explicit x256(const SomeClass& c): c_(c)
      {
      }
    };
    struct x16
    {
      const SomeClass& c_;
      explicit x16(const SomeClass& c): c_(c)
      {
      }
    };

    struct x4
    {
      const SomeClass& c_;
      explicit x4(const SomeClass& c): c_(c)
      {
      }
    };

    x256 output265() const
    {
      return x256(*this);
    }

    x16 output16() const
    {
      return x16(*this);
    }

    x4 output4() const
    {
      return x4(*this);
    }

    friend std::ostream& operator<<( std::ostream& out, const SomeClass::x256& c ) {
        out << std::endl;
        for ( unsigned u = 0; u < 256; u++ ) {
            out << u << " = " << c.c_.m_256[u] << std::endl;
        }
        return out;
    } // operator<<
    friend std::ostream& operator<<( std::ostream& out, const SomeClass::x16& c ) {
        //...
        return out;
    } // operator<<
    friend std::ostream& operator<<( std::ostream& out, const SomeClass::x4& c ) {
        //...
        return out;
    } // operator<<
}; // SomeClass

void testSomeClass()
{
  SomeClass someClass;

  std::cout << someClass.output265() << someClass.output16() << someClass.output4() << std::endl;
}
于 2016-04-08T06:21:13.340 回答
1

添加一些方式,例如成员到你的类来决定输出格式:

public:
    enum OutputStyle 
    {
        M_256,
        M_16,
        M_4,
    };
    OutputStyle style() const {return style_;}

 private:  
     mutable OutputStyle style_ = M_256;

添加一些方法,例如函数调用运算符来设置:

public:
    SomeClass const& operator()(OutputStyle s) const
    {
        style_ = s;
        return *this;
    }

让 << 运算符考虑它:

std::ostream& operator<<( std::ostream& out, const SomeClass& c ) 
{
    switch( c.style() )
    {
    default:
        assert(!"defective operator <<");
    case SomeClass::M_256:
        // ... output like M_256 here 
        break; 
    case SomeClass::M_16: 
        // ... output like M_16 here
        break; 
    case SomeClass::M_4:
        // ... output like M_4 here
        break;
    }
} 

然后您可以在输出之前或期间更改它:

    SomeClass x; // <- has style M_256

    x(SomeClass::M_16);

    std::cout << "current:" << x << std::endl
              << "with M_4:" << x(SomeClass::M_4) << std::endl;
于 2016-04-08T06:31:43.310 回答